summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/SCsub191
-rw-r--r--modules/bullet/SCsub_with_lib33
-rw-r--r--modules/bullet/area_bullet.cpp284
-rw-r--r--modules/bullet/area_bullet.h169
-rw-r--r--modules/bullet/btRayShape.cpp94
-rw-r--r--modules/bullet/btRayShape.h87
-rw-r--r--modules/bullet/bullet_physics_server.cpp1342
-rw-r--r--modules/bullet/bullet_physics_server.h359
-rw-r--r--modules/bullet/bullet_types_converter.cpp94
-rw-r--r--modules/bullet/bullet_types_converter.h57
-rw-r--r--modules/bullet/bullet_utilities.h44
-rw-r--r--modules/bullet/collision_object_bullet.cpp320
-rw-r--r--modules/bullet/collision_object_bullet.h234
-rw-r--r--modules/bullet/cone_twist_joint_bullet.cpp111
-rw-r--r--modules/bullet/cone_twist_joint_bullet.h58
-rw-r--r--modules/bullet/config.py6
-rw-r--r--modules/bullet/constraint_bullet.cpp50
-rw-r--r--modules/bullet/constraint_bullet.h64
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp241
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h65
-rw-r--r--modules/bullet/godot_collision_configuration.cpp91
-rw-r--r--modules/bullet/godot_collision_configuration.h50
-rw-r--r--modules/bullet/godot_collision_dispatcher.cpp54
-rw-r--r--modules/bullet/godot_collision_dispatcher.h48
-rw-r--r--modules/bullet/godot_motion_state.h96
-rw-r--r--modules/bullet/godot_ray_world_algorithm.cpp104
-rw-r--r--modules/bullet/godot_ray_world_algorithm.h83
-rw-r--r--modules/bullet/godot_result_callbacks.cpp291
-rw-r--r--modules/bullet/godot_result_callbacks.h189
-rw-r--r--modules/bullet/hinge_joint_bullet.cpp163
-rw-r--r--modules/bullet/hinge_joint_bullet.h54
-rw-r--r--modules/bullet/joint_bullet.cpp38
-rw-r--r--modules/bullet/joint_bullet.h49
-rw-r--r--modules/bullet/pin_joint_bullet.cpp112
-rw-r--r--modules/bullet/pin_joint_bullet.h57
-rw-r--r--modules/bullet/register_types.cpp47
-rw-r--r--modules/bullet/register_types.h37
-rw-r--r--modules/bullet/rid_bullet.h50
-rw-r--r--modules/bullet/rigid_body_bullet.cpp1009
-rw-r--r--modules/bullet/rigid_body_bullet.h304
-rw-r--r--modules/bullet/shape_bullet.cpp435
-rw-r--r--modules/bullet/shape_bullet.h225
-rw-r--r--modules/bullet/shape_owner_bullet.cpp32
-rw-r--r--modules/bullet/shape_owner_bullet.h52
-rw-r--r--modules/bullet/slider_joint_bullet.cpp385
-rw-r--r--modules/bullet/slider_joint_bullet.h118
-rw-r--r--modules/bullet/soft_body_bullet.cpp303
-rw-r--r--modules/bullet/soft_body_bullet.h136
-rw-r--r--modules/bullet/space_bullet.cpp1163
-rw-r--r--modules/bullet/space_bullet.h177
-rw-r--r--modules/dds/texture_loader_dds.cpp2
-rw-r--r--modules/enet/SCsub2
-rw-r--r--modules/etc/config.py4
-rw-r--r--modules/freetype/SCsub4
-rw-r--r--modules/gdnative/SCsub149
-rw-r--r--modules/gdnative/config.py8
-rw-r--r--modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml17
-rw-r--r--modules/gdnative/doc_classes/GDNative.xml57
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml57
-rw-r--r--modules/gdnative/doc_classes/NativeScript.xml55
-rw-r--r--modules/gdnative/gd_native_library_editor.cpp4
-rw-r--r--modules/gdnative/gdnative.cpp83
-rw-r--r--modules/gdnative/gdnative.h14
-rw-r--r--modules/gdnative/gdnative/basis.cpp2
-rw-r--r--modules/gdnative/gdnative/gdnative.cpp2
-rw-r--r--modules/gdnative/gdnative/pool_arrays.cpp262
-rw-r--r--modules/gdnative/gdnative/string.cpp28
-rw-r--r--modules/gdnative/gdnative/string_name.cpp91
-rw-r--r--modules/gdnative/gdnative/variant.cpp5
-rw-r--r--modules/gdnative/gdnative_api.json5734
-rw-r--r--modules/gdnative/include/gdnative/array.h9
-rw-r--r--modules/gdnative/include/gdnative/basis.h11
-rw-r--r--modules/gdnative/include/gdnative/color.h9
-rw-r--r--modules/gdnative/include/gdnative/dictionary.h9
-rw-r--r--modules/gdnative/include/gdnative/gdnative.h28
-rw-r--r--modules/gdnative/include/gdnative/node_path.h9
-rw-r--r--modules/gdnative/include/gdnative/plane.h9
-rw-r--r--modules/gdnative/include/gdnative/pool_arrays.h133
-rw-r--r--modules/gdnative/include/gdnative/quat.h9
-rw-r--r--modules/gdnative/include/gdnative/rect2.h9
-rw-r--r--modules/gdnative/include/gdnative/rect3.h9
-rw-r--r--modules/gdnative/include/gdnative/rid.h9
-rw-r--r--modules/gdnative/include/gdnative/string.h10
-rw-r--r--modules/gdnative/include/gdnative/string_name.h77
-rw-r--r--modules/gdnative/include/gdnative/transform.h9
-rw-r--r--modules/gdnative/include/gdnative/transform2d.h9
-rw-r--r--modules/gdnative/include/gdnative/variant.h11
-rw-r--r--modules/gdnative/include/gdnative/vector2.h9
-rw-r--r--modules/gdnative/include/gdnative/vector3.h9
-rw-r--r--modules/gdnative/include/gdnative_api_struct.h723
-rw-r--r--modules/gdnative/include/nativearvr/godot_nativearvr.h79
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h36
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h171
-rw-r--r--modules/gdnative/nativearvr/SCsub13
-rw-r--r--modules/gdnative/nativearvr/arvr_interface_gdnative.cpp398
-rw-r--r--modules/gdnative/nativearvr/arvr_interface_gdnative.h86
-rw-r--r--modules/gdnative/nativearvr/config.py5
-rw-r--r--modules/gdnative/nativearvr/register_types.cpp39
-rw-r--r--modules/gdnative/nativearvr/register_types.h32
-rw-r--r--modules/gdnative/nativescript/SCsub4
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp8
-rw-r--r--modules/gdnative/nativescript/api_generator.h2
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp58
-rw-r--r--modules/gdnative/nativescript/nativescript.h9
-rw-r--r--modules/gdnative/nativescript/register_types.cpp50
-rw-r--r--modules/gdnative/pluginscript/SCsub9
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp181
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h90
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp435
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h132
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.cpp113
-rw-r--r--modules/gdnative/pluginscript/pluginscript_loader.h62
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.cpp449
-rw-r--r--modules/gdnative/pluginscript/pluginscript_script.h127
-rw-r--r--modules/gdnative/pluginscript/register_types.cpp118
-rw-r--r--modules/gdnative/pluginscript/register_types.h31
-rw-r--r--modules/gdnative/register_types.cpp80
-rw-r--r--modules/gdscript/gd_compiler.cpp4
-rw-r--r--modules/gdscript/gd_editor.cpp20
-rw-r--r--modules/gdscript/gd_function.cpp423
-rw-r--r--modules/gdscript/gd_functions.cpp22
-rw-r--r--modules/gdscript/gd_functions.h2
-rw-r--r--modules/gdscript/gd_parser.cpp5
-rw-r--r--modules/gdscript/gd_script.cpp5
-rw-r--r--modules/gdscript/gd_script.h2
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml52
-rw-r--r--modules/gridmap/grid_map.cpp48
-rw-r--r--modules/gridmap/grid_map.h7
-rw-r--r--modules/hdr/image_loader_hdr.cpp4
-rw-r--r--modules/mobile_vr/SCsub13
-rw-r--r--modules/mobile_vr/config.py12
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml134
-rw-r--r--modules/mobile_vr/mobile_interface.cpp504
-rw-r--r--modules/mobile_vr/mobile_interface.h152
-rw-r--r--modules/mobile_vr/register_types.cpp43
-rw-r--r--modules/mobile_vr/register_types.h31
-rw-r--r--modules/mobile_vr/shaders/SCsub7
-rw-r--r--modules/mobile_vr/shaders/lens_distorted.glsl59
-rw-r--r--modules/mono/SCsub208
-rw-r--r--modules/mono/config.py184
-rw-r--r--modules/mono/csharp_script.cpp2061
-rw-r--r--modules/mono/csharp_script.h347
-rw-r--r--modules/mono/doc_classes/@C#.xml15
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml21
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml43
-rw-r--r--modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs369
-rw-r--r--modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs58
-rw-r--r--modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj45
-rw-r--r--modules/mono/editor/GodotSharpTools/GodotSharpTools.sln17
-rw-r--r--modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs14
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs52
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs216
-rw-r--r--modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs17
-rw-r--r--modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs27
-rw-r--r--modules/mono/editor/GodotSharpTools/StringExtensions.cs52
-rw-r--r--modules/mono/editor/bindings_generator.cpp2158
-rw-r--r--modules/mono/editor/bindings_generator.h436
-rw-r--r--modules/mono/editor/csharp_project.cpp120
-rw-r--r--modules/mono/editor/csharp_project.h44
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp515
-rw-r--r--modules/mono/editor/godotsharp_builds.h101
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp286
-rw-r--r--modules/mono/editor/godotsharp_editor.h109
-rw-r--r--modules/mono/editor/mono_bottom_panel.cpp458
-rw-r--r--modules/mono/editor/mono_bottom_panel.h147
-rw-r--r--modules/mono/editor/mono_build_info.h64
-rw-r--r--modules/mono/editor/monodevelop_instance.cpp81
-rw-r--r--modules/mono/editor/monodevelop_instance.h50
-rw-r--r--modules/mono/editor/net_solution.cpp130
-rw-r--r--modules/mono/editor/net_solution.h57
-rw-r--r--modules/mono/glue/cs_files/Basis.cs520
-rw-r--r--modules/mono/glue/cs_files/Color.cs590
-rw-r--r--modules/mono/glue/cs_files/Error.cs48
-rw-r--r--modules/mono/glue/cs_files/ExportAttribute.cs17
-rw-r--r--modules/mono/glue/cs_files/GD.cs191
-rw-r--r--modules/mono/glue/cs_files/GodotMethodAttribute.cs17
-rw-r--r--modules/mono/glue/cs_files/GodotSynchronizationContext.cs26
-rw-r--r--modules/mono/glue/cs_files/GodotTaskScheduler.cs94
-rw-r--r--modules/mono/glue/cs_files/IAwaitable.cs12
-rw-r--r--modules/mono/glue/cs_files/IAwaiter.cs19
-rw-r--r--modules/mono/glue/cs_files/MarshalUtils.cs36
-rw-r--r--modules/mono/glue/cs_files/Mathf.cs234
-rw-r--r--modules/mono/glue/cs_files/Plane.cs209
-rw-r--r--modules/mono/glue/cs_files/Quat.cs328
-rw-r--r--modules/mono/glue/cs_files/RPCAttributes.cs16
-rw-r--r--modules/mono/glue/cs_files/Rect2.cs233
-rw-r--r--modules/mono/glue/cs_files/Rect3.cs477
-rw-r--r--modules/mono/glue/cs_files/SignalAwaiter.cs59
-rw-r--r--modules/mono/glue/cs_files/StringExtensions.cs962
-rw-r--r--modules/mono/glue/cs_files/ToolAttribute.cs7
-rw-r--r--modules/mono/glue/cs_files/Transform.cs174
-rw-r--r--modules/mono/glue/cs_files/Transform2D.cs356
-rw-r--r--modules/mono/glue/cs_files/Vector2.cs362
-rw-r--r--modules/mono/glue/cs_files/Vector3.cs420
-rw-r--r--modules/mono/glue/glue_header.h302
-rw-r--r--modules/mono/godotsharp_defs.h41
-rw-r--r--modules/mono/godotsharp_dirs.cpp201
-rw-r--r--modules/mono/godotsharp_dirs.h58
-rw-r--r--modules/mono/mono_gc_handle.cpp81
-rw-r--r--modules/mono/mono_gc_handle.h63
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp784
-rw-r--r--modules/mono/mono_gd/gd_mono.h226
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp359
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h121
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp413
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h130
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp364
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h74
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h59
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp66
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h42
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp175
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h61
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp859
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h219
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp227
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h81
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp367
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h186
-rw-r--r--modules/mono/mono_reg_utils.py114
-rw-r--r--modules/mono/register_types.cpp72
-rw-r--r--modules/mono/register_types.h31
-rw-r--r--modules/mono/signal_awaiter_utils.cpp144
-rw-r--r--modules/mono/signal_awaiter_utils.h70
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp228
-rw-r--r--modules/mono/utils/mono_reg_utils.h54
-rw-r--r--modules/mono/utils/path_utils.cpp111
-rw-r--r--modules/mono/utils/path_utils.h53
-rw-r--r--modules/mono/utils/string_utils.cpp157
-rw-r--r--modules/mono/utils/string_utils.h44
-rw-r--r--modules/ogg/SCsub2
-rw-r--r--modules/openssl/SCsub2
-rw-r--r--modules/openssl/stream_peer_openssl.cpp60
-rw-r--r--modules/openssl/stream_peer_openssl.h5
-rw-r--r--modules/opus/SCsub4
-rw-r--r--modules/opus/audio_stream_opus.cpp16
-rw-r--r--modules/opus/audio_stream_opus.h6
-rw-r--r--modules/pvr/texture_loader_pvr.cpp2
-rw-r--r--modules/recast/SCsub6
-rw-r--r--modules/recast/config.py2
-rw-r--r--modules/regex/SCsub4
-rw-r--r--modules/squish/SCsub2
-rw-r--r--modules/squish/config.py4
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp11
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.h4
-rw-r--r--modules/svg/image_loader_svg.cpp2
-rw-r--r--modules/tga/image_loader_tga.cpp4
-rw-r--r--modules/theora/SCsub6
-rw-r--r--modules/theora/video_stream_theora.cpp4
-rw-r--r--modules/theora/video_stream_theora.h4
-rw-r--r--modules/tinyexr/config.py4
-rw-r--r--modules/visual_script/visual_script.cpp24
-rw-r--r--modules/visual_script/visual_script.h7
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp97
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h5
-rw-r--r--modules/visual_script/visual_script_editor.cpp220
-rw-r--r--modules/visual_script/visual_script_expression.cpp4
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp16
-rw-r--r--modules/visual_script/visual_script_nodes.cpp11
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp10
-rw-r--r--modules/visual_script/visual_script_yield_nodes.h2
-rw-r--r--modules/vorbis/SCsub4
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp18
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.h6
-rw-r--r--modules/webm/SCsub8
-rw-r--r--modules/webm/libvpx/SCsub2
-rw-r--r--modules/webm/video_stream_webm.cpp6
-rw-r--r--modules/webm/video_stream_webm.h4
-rw-r--r--modules/webp/SCsub2
269 files changed, 41655 insertions, 1402 deletions
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
new file mode 100644
index 0000000000..7a37cca130
--- /dev/null
+++ b/modules/bullet/SCsub
@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# build only version 2
+# Bullet 2.87
+bullet_src__2_x = [
+ # BulletCollision
+ "BulletCollision/BroadphaseCollision/btAxisSweep3.cpp"
+ , "BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp"
+ , "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp"
+ , "BulletCollision/BroadphaseCollision/btDbvt.cpp"
+ , "BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp"
+ , "BulletCollision/BroadphaseCollision/btDispatcher.cpp"
+ , "BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp"
+ , "BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp"
+ , "BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp"
+ , "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp"
+ , "BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp"
+ , "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp"
+ , "BulletCollision/CollisionDispatch/btCollisionObject.cpp"
+ , "BulletCollision/CollisionDispatch/btCollisionWorld.cpp"
+ , "BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp"
+ , "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp"
+ , "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btGhostObject.cpp"
+ , "BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp"
+ , "BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp"
+ , "BulletCollision/CollisionDispatch/btManifoldResult.cpp"
+ , "BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp"
+ , "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp"
+ , "BulletCollision/CollisionDispatch/btUnionFind.cpp"
+ , "BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp"
+ , "BulletCollision/CollisionShapes/btBoxShape.cpp"
+ , "BulletCollision/CollisionShapes/btBox2dShape.cpp"
+ , "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp"
+ , "BulletCollision/CollisionShapes/btCapsuleShape.cpp"
+ , "BulletCollision/CollisionShapes/btCollisionShape.cpp"
+ , "BulletCollision/CollisionShapes/btCompoundShape.cpp"
+ , "BulletCollision/CollisionShapes/btConcaveShape.cpp"
+ , "BulletCollision/CollisionShapes/btConeShape.cpp"
+ , "BulletCollision/CollisionShapes/btConvexHullShape.cpp"
+ , "BulletCollision/CollisionShapes/btConvexInternalShape.cpp"
+ , "BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp"
+ , "BulletCollision/CollisionShapes/btConvexPolyhedron.cpp"
+ , "BulletCollision/CollisionShapes/btConvexShape.cpp"
+ , "BulletCollision/CollisionShapes/btConvex2dShape.cpp"
+ , "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp"
+ , "BulletCollision/CollisionShapes/btCylinderShape.cpp"
+ , "BulletCollision/CollisionShapes/btEmptyShape.cpp"
+ , "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp"
+ , "BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp"
+ , "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp"
+ , "BulletCollision/CollisionShapes/btMultiSphereShape.cpp"
+ , "BulletCollision/CollisionShapes/btOptimizedBvh.cpp"
+ , "BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp"
+ , "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp"
+ , "BulletCollision/CollisionShapes/btShapeHull.cpp"
+ , "BulletCollision/CollisionShapes/btSphereShape.cpp"
+ , "BulletCollision/CollisionShapes/btStaticPlaneShape.cpp"
+ , "BulletCollision/CollisionShapes/btStridingMeshInterface.cpp"
+ , "BulletCollision/CollisionShapes/btTetrahedronShape.cpp"
+ , "BulletCollision/CollisionShapes/btTriangleBuffer.cpp"
+ , "BulletCollision/CollisionShapes/btTriangleCallback.cpp"
+ , "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp"
+ , "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp"
+ , "BulletCollision/CollisionShapes/btTriangleMesh.cpp"
+ , "BulletCollision/CollisionShapes/btTriangleMeshShape.cpp"
+ , "BulletCollision/CollisionShapes/btUniformScalingShape.cpp"
+ , "BulletCollision/Gimpact/btContactProcessing.cpp"
+ , "BulletCollision/Gimpact/btGenericPoolAllocator.cpp"
+ , "BulletCollision/Gimpact/btGImpactBvh.cpp"
+ , "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp"
+ , "BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp"
+ , "BulletCollision/Gimpact/btGImpactShape.cpp"
+ , "BulletCollision/Gimpact/btTriangleShapeEx.cpp"
+ , "BulletCollision/Gimpact/gim_box_set.cpp"
+ , "BulletCollision/Gimpact/gim_contact.cpp"
+ , "BulletCollision/Gimpact/gim_memory.cpp"
+ , "BulletCollision/Gimpact/gim_tri_collision.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btConvexCast.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp"
+ , "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp"
+
+ # BulletDynamics
+ , "BulletDynamics/Character/btKinematicCharacterController.cpp"
+ , "BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btContactConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btFixedConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btGearConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btHingeConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp"
+ , "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp"
+ , "BulletDynamics/ConstraintSolver/btSliderConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btTypedConstraint.cpp"
+ , "BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp"
+ , "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp"
+ , "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp"
+ , "BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp"
+ , "BulletDynamics/Dynamics/btRigidBody.cpp"
+ , "BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp"
+ #, "BulletDynamics/Dynamics/Bullet-C-API.cpp"
+ , "BulletDynamics/Vehicle/btRaycastVehicle.cpp"
+ , "BulletDynamics/Vehicle/btWheelInfo.cpp"
+ , "BulletDynamics/Featherstone/btMultiBody.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyConstraint.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp"
+ , "BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp"
+ , "BulletDynamics/MLCPSolvers/btDantzigLCP.cpp"
+ , "BulletDynamics/MLCPSolvers/btMLCPSolver.cpp"
+ , "BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp"
+
+ # BulletInverseDynamics
+ , "BulletInverseDynamics/IDMath.cpp"
+ , "BulletInverseDynamics/MultiBodyTree.cpp"
+ , "BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp"
+ , "BulletInverseDynamics/details/MultiBodyTreeImpl.cpp"
+
+ # BulletSoftBody
+ , "BulletSoftBody/btSoftBody.cpp"
+ , "BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp"
+ , "BulletSoftBody/btSoftBodyHelpers.cpp"
+ , "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp"
+ , "BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp"
+ , "BulletSoftBody/btSoftRigidDynamicsWorld.cpp"
+ , "BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp"
+ , "BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp"
+ , "BulletSoftBody/btDefaultSoftBodySolver.cpp"
+
+ # clew
+ , "clew/clew.c"
+
+ # LinearMath
+ , "LinearMath/btAlignedAllocator.cpp"
+ , "LinearMath/btConvexHull.cpp"
+ , "LinearMath/btConvexHullComputer.cpp"
+ , "LinearMath/btGeometryUtil.cpp"
+ , "LinearMath/btPolarDecomposition.cpp"
+ , "LinearMath/btQuickprof.cpp"
+ , "LinearMath/btSerializer.cpp"
+ , "LinearMath/btSerializer64.cpp"
+ , "LinearMath/btThreads.cpp"
+ , "LinearMath/btVector3.cpp"
+ ]
+
+thirdparty_dir = "#thirdparty/bullet/"
+thirdparty_src = thirdparty_dir + "src/"
+
+bullet_sources = [thirdparty_src + file for file in bullet_src__2_x]
+
+# include headers
+env.Append(CPPPATH=[thirdparty_src])
+
+env.add_source_files(env.modules_sources, bullet_sources)
+
+# Godot source files
+env.add_source_files(env.modules_sources, "*.cpp")
+
+Export('env')
diff --git a/modules/bullet/SCsub_with_lib b/modules/bullet/SCsub_with_lib
new file mode 100644
index 0000000000..b362a686ff
--- /dev/null
+++ b/modules/bullet/SCsub_with_lib
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+Import('env')
+
+thirdparty_dir = "#thirdparty/bullet/"
+thirdparty_lib = thirdparty_dir + "Win64/lib/"
+
+bullet_libs = [
+ "Bullet2FileLoader",
+ "Bullet3Collision",
+ "Bullet3Common",
+ "Bullet3Dynamics",
+ "Bullet3Geometry",
+ "Bullet3OpenCL_clew",
+ "BulletCollision",
+ "BulletDynamics",
+ "BulletInverseDynamics",
+ "BulletSoftBody",
+ "LinearMath"
+ ]
+
+thirdparty_src = thirdparty_dir + "src/"
+# include headers
+env.Append(CPPPATH=[thirdparty_src])
+
+# lib
+env.Append(LIBPATH=[thirdparty_dir + "/Win64/lib/"])
+
+bullet_libs = [file+'.lib' for file in bullet_libs]
+# LIBS doesn't work in windows
+env.Append(LINKFLAGS=bullet_libs)
+
+env.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
new file mode 100644
index 0000000000..54024b4f90
--- /dev/null
+++ b/modules/bullet/area_bullet.cpp
@@ -0,0 +1,284 @@
+/*************************************************************************/
+/* area_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "area_bullet.h"
+#include "BulletCollision/CollisionDispatch/btGhostObject.h"
+#include "btBulletCollisionCommon.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "collision_object_bullet.h"
+#include "space_bullet.h"
+
+AreaBullet::AreaBullet()
+ : RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_AREA),
+ monitorable(true),
+ isScratched(false),
+ spOv_mode(PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED),
+ spOv_gravityPoint(false),
+ spOv_gravityPointDistanceScale(0),
+ spOv_gravityPointAttenuation(1),
+ spOv_gravityVec(0, -1, 0),
+ spOv_gravityMag(10),
+ spOv_linearDump(0.1),
+ spOv_angularDump(1),
+ spOv_priority(0) {
+
+ btGhost = bulletnew(btGhostObject);
+ btGhost->setCollisionShape(compoundShape);
+ setupBulletCollisionObject(btGhost);
+ /// Collision objects with a callback still have collision response with dynamic rigid bodies.
+ /// In order to use collision objects as trigger, you have to disable the collision response.
+ set_collision_enabled(false);
+
+ for (int i = 0; i < 5; ++i)
+ call_event_res_ptr[i] = &call_event_res[i];
+}
+
+AreaBullet::~AreaBullet() {
+ remove_all_overlapping_instantly();
+}
+
+void AreaBullet::dispatch_callbacks() {
+ if (!isScratched)
+ return;
+ isScratched = false;
+
+ // Reverse order because I've to remove EXIT objects
+ for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
+ OverlappingObjectData &otherObj = overlappingObjects[i];
+
+ switch (otherObj.state) {
+ case OVERLAP_STATE_ENTER:
+ otherObj.state = OVERLAP_STATE_INSIDE;
+ call_event(otherObj.object, PhysicsServer::AREA_BODY_ADDED);
+ otherObj.object->on_enter_area(this);
+ break;
+ case OVERLAP_STATE_EXIT:
+ call_event(otherObj.object, PhysicsServer::AREA_BODY_REMOVED);
+ otherObj.object->on_exit_area(this);
+ overlappingObjects.remove(i); // Remove after callback
+ break;
+ }
+ }
+}
+
+void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer::AreaBodyStatus p_status) {
+
+ InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())];
+ Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id);
+
+ if (!areaGodoObject) {
+ event.event_callback_id = 0;
+ return;
+ }
+
+ call_event_res[0] = p_status;
+ call_event_res[1] = p_otherObject->get_self(); // Other body
+ call_event_res[2] = p_otherObject->get_instance_id(); // instance ID
+ call_event_res[3] = 0; // other_body_shape ID
+ call_event_res[4] = 0; // self_shape ID
+
+ Variant::CallError outResp;
+ areaGodoObject->call(event.event_callback_method, (const Variant **)call_event_res_ptr, 5, outResp);
+}
+
+void AreaBullet::scratch() {
+ if (isScratched)
+ return;
+ isScratched = true;
+}
+
+void AreaBullet::remove_all_overlapping_instantly() {
+ CollisionObjectBullet *supportObject;
+ for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
+ supportObject = overlappingObjects[i].object;
+ call_event(supportObject, PhysicsServer::AREA_BODY_REMOVED);
+ supportObject->on_exit_area(this);
+ }
+ overlappingObjects.clear();
+}
+
+void AreaBullet::remove_overlapping_instantly(CollisionObjectBullet *p_object) {
+ CollisionObjectBullet *supportObject;
+ for (int i = overlappingObjects.size() - 1; 0 <= i; --i) {
+ supportObject = overlappingObjects[i].object;
+ if (supportObject == p_object) {
+ call_event(supportObject, PhysicsServer::AREA_BODY_REMOVED);
+ supportObject->on_exit_area(this);
+ overlappingObjects.remove(i);
+ break;
+ }
+ }
+}
+
+int AreaBullet::find_overlapping_object(CollisionObjectBullet *p_colObj) {
+ const int size = overlappingObjects.size();
+ for (int i = 0; i < size; ++i) {
+ if (overlappingObjects[i].object == p_colObj) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void AreaBullet::set_monitorable(bool p_monitorable) {
+ monitorable = p_monitorable;
+}
+
+bool AreaBullet::is_monitoring() const {
+ return get_godot_object_flags() & GOF_IS_MONITORING_AREA;
+}
+
+void AreaBullet::reload_body() {
+ if (space) {
+ space->remove_area(this);
+ space->add_area(this);
+ }
+}
+
+void AreaBullet::set_space(SpaceBullet *p_space) {
+ // Clear the old space if there is one
+ if (space) {
+ isScratched = false;
+
+ // Remove this object form the physics world
+ space->remove_area(this);
+ }
+
+ space = p_space;
+
+ if (space) {
+ space->add_area(this);
+ }
+}
+
+void AreaBullet::on_collision_filters_change() {
+ if (space) {
+ space->reload_collision_filters(this);
+ }
+}
+
+void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) {
+ scratch();
+ overlappingObjects.push_back(OverlappingObjectData(p_otherObject, OVERLAP_STATE_ENTER));
+ p_otherObject->notify_new_overlap(this);
+}
+
+void AreaBullet::put_overlap_as_exit(int p_index) {
+ scratch();
+ overlappingObjects[p_index].state = OVERLAP_STATE_EXIT;
+}
+
+void AreaBullet::put_overlap_as_inside(int p_index) {
+ // This check is required to be sure this body was inside
+ if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) {
+ overlappingObjects[p_index].state = OVERLAP_STATE_INSIDE;
+ }
+}
+
+void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) {
+ switch (p_param) {
+ case PhysicsServer::AREA_PARAM_GRAVITY:
+ set_spOv_gravityMag(p_value);
+ break;
+ case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ set_spOv_gravityVec(p_value);
+ break;
+ case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
+ set_spOv_linearDump(p_value);
+ break;
+ case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ set_spOv_angularDump(p_value);
+ break;
+ case PhysicsServer::AREA_PARAM_PRIORITY:
+ set_spOv_priority(p_value);
+ break;
+ case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
+ set_spOv_gravityPoint(p_value);
+ break;
+ case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ set_spOv_gravityPointDistanceScale(p_value);
+ break;
+ case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ set_spOv_gravityPointAttenuation(p_value);
+ break;
+ default:
+ print_line("The Bullet areas dosn't suppot this param: " + itos(p_param));
+ }
+}
+
+Variant AreaBullet::get_param(PhysicsServer::AreaParameter p_param) const {
+ switch (p_param) {
+ case PhysicsServer::AREA_PARAM_GRAVITY:
+ return spOv_gravityMag;
+ case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ return spOv_gravityVec;
+ case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
+ return spOv_linearDump;
+ case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ return spOv_angularDump;
+ case PhysicsServer::AREA_PARAM_PRIORITY:
+ return spOv_priority;
+ case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
+ return spOv_gravityPoint;
+ case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ return spOv_gravityPointDistanceScale;
+ case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ return spOv_gravityPointAttenuation;
+ default:
+ print_line("The Bullet areas dosn't suppot this param: " + itos(p_param));
+ return Variant();
+ }
+}
+
+void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method) {
+ InOutEventCallback &ev = eventsCallbacks[static_cast<int>(p_callbackObjectType)];
+ ev.event_callback_id = p_id;
+ ev.event_callback_method = p_method;
+
+ /// Set if monitoring
+ if (eventsCallbacks[0].event_callback_id || eventsCallbacks[1].event_callback_id) {
+ set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA);
+ } else {
+ set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA));
+ }
+}
+
+bool AreaBullet::has_event_callback(Type p_callbackObjectType) {
+ return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id;
+}
+
+void AreaBullet::on_enter_area(AreaBullet *p_area) {
+}
+
+void AreaBullet::on_exit_area(AreaBullet *p_area) {
+ CollisionObjectBullet::on_exit_area(p_area);
+}
diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h
new file mode 100644
index 0000000000..f6e3b7e902
--- /dev/null
+++ b/modules/bullet/area_bullet.h
@@ -0,0 +1,169 @@
+/*************************************************************************/
+/* area_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef AREABULLET_H
+#define AREABULLET_H
+
+#include "collision_object_bullet.h"
+#include "core/vector.h"
+#include "servers/physics_server.h"
+#include "space_bullet.h"
+
+class btGhostObject;
+
+class AreaBullet : public RigidCollisionObjectBullet {
+ friend void SpaceBullet::check_ghost_overlaps();
+
+public:
+ struct InOutEventCallback {
+ ObjectID event_callback_id;
+ StringName event_callback_method;
+
+ InOutEventCallback()
+ : event_callback_id(0) {}
+ };
+
+ enum OverlapState {
+ OVERLAP_STATE_DIRTY = 0, // Mark processed overlaps
+ OVERLAP_STATE_INSIDE, // Mark old overlap
+ OVERLAP_STATE_ENTER, // Mark just enter overlap
+ OVERLAP_STATE_EXIT // Mark ended overlaps
+ };
+
+ struct OverlappingObjectData {
+ CollisionObjectBullet *object;
+ OverlapState state;
+
+ OverlappingObjectData()
+ : object(NULL), state(OVERLAP_STATE_ENTER) {}
+ OverlappingObjectData(CollisionObjectBullet *p_object, OverlapState p_state)
+ : object(p_object), state(p_state) {}
+ OverlappingObjectData(const OverlappingObjectData &other) {
+ operator=(other);
+ }
+ void operator=(const OverlappingObjectData &other) {
+ object = other.object;
+ state = other.state;
+ }
+ };
+
+private:
+ // These are used by function callEvent. Instead to create this each call I create if one time.
+ Variant call_event_res[5];
+ Variant *call_event_res_ptr[5];
+
+ btGhostObject *btGhost;
+ Vector<OverlappingObjectData> overlappingObjects;
+ bool monitorable;
+
+ PhysicsServer::AreaSpaceOverrideMode spOv_mode;
+ bool spOv_gravityPoint;
+ real_t spOv_gravityPointDistanceScale;
+ real_t spOv_gravityPointAttenuation;
+ Vector3 spOv_gravityVec;
+ real_t spOv_gravityMag;
+ real_t spOv_linearDump;
+ real_t spOv_angularDump;
+ int spOv_priority;
+
+ bool isScratched;
+
+ InOutEventCallback eventsCallbacks[2];
+
+public:
+ AreaBullet();
+ ~AreaBullet();
+
+ _FORCE_INLINE_ btGhostObject *get_bt_ghost() const { return btGhost; }
+ int find_overlapping_object(CollisionObjectBullet *p_colObj);
+
+ void set_monitorable(bool p_monitorable);
+ _FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
+
+ bool is_monitoring() const;
+
+ _FORCE_INLINE_ void set_spOv_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) { spOv_mode = p_mode; }
+ _FORCE_INLINE_ PhysicsServer::AreaSpaceOverrideMode get_spOv_mode() { return spOv_mode; }
+
+ _FORCE_INLINE_ void set_spOv_gravityPoint(bool p_isGP) { spOv_gravityPoint = p_isGP; }
+ _FORCE_INLINE_ bool is_spOv_gravityPoint() { return spOv_gravityPoint; }
+
+ _FORCE_INLINE_ void set_spOv_gravityPointDistanceScale(real_t p_GPDS) { spOv_gravityPointDistanceScale = p_GPDS; }
+ _FORCE_INLINE_ real_t get_spOv_gravityPointDistanceScale() { return spOv_gravityPointDistanceScale; }
+
+ _FORCE_INLINE_ void set_spOv_gravityPointAttenuation(real_t p_GPA) { spOv_gravityPointAttenuation = p_GPA; }
+ _FORCE_INLINE_ real_t get_spOv_gravityPointAttenuation() { return spOv_gravityPointAttenuation; }
+
+ _FORCE_INLINE_ void set_spOv_gravityVec(Vector3 p_vec) { spOv_gravityVec = p_vec; }
+ _FORCE_INLINE_ const Vector3 &get_spOv_gravityVec() const { return spOv_gravityVec; }
+
+ _FORCE_INLINE_ void set_spOv_gravityMag(real_t p_gravityMag) { spOv_gravityMag = p_gravityMag; }
+ _FORCE_INLINE_ real_t get_spOv_gravityMag() { return spOv_gravityMag; }
+
+ _FORCE_INLINE_ void set_spOv_linearDump(real_t p_linearDump) { spOv_linearDump = p_linearDump; }
+ _FORCE_INLINE_ real_t get_spOv_linearDamp() { return spOv_linearDump; }
+
+ _FORCE_INLINE_ void set_spOv_angularDump(real_t p_angularDump) { spOv_angularDump = p_angularDump; }
+ _FORCE_INLINE_ real_t get_spOv_angularDamp() { return spOv_angularDump; }
+
+ _FORCE_INLINE_ void set_spOv_priority(int p_priority) { spOv_priority = p_priority; }
+ _FORCE_INLINE_ int get_spOv_priority() { return spOv_priority; }
+
+ virtual void reload_body();
+ virtual void set_space(SpaceBullet *p_space);
+
+ virtual void dispatch_callbacks();
+ void call_event(CollisionObjectBullet *p_otherObject, PhysicsServer::AreaBodyStatus p_status);
+ void set_on_state_change(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void scratch();
+
+ void remove_all_overlapping_instantly();
+ // Dispatch the callbacks and removes from overlapping list
+ void remove_overlapping_instantly(CollisionObjectBullet *p_object);
+
+ virtual void on_collision_filters_change();
+ virtual void on_collision_checker_start() {}
+
+ void add_overlap(CollisionObjectBullet *p_otherObject);
+ void put_overlap_as_exit(int p_index);
+ void put_overlap_as_inside(int p_index);
+
+ void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value);
+ Variant get_param(PhysicsServer::AreaParameter p_param) const;
+
+ void set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method);
+ bool has_event_callback(Type p_callbackObjectType);
+
+ virtual void on_enter_area(AreaBullet *p_area);
+ virtual void on_exit_area(AreaBullet *p_area);
+};
+
+#endif
diff --git a/modules/bullet/btRayShape.cpp b/modules/bullet/btRayShape.cpp
new file mode 100644
index 0000000000..ac95faaac6
--- /dev/null
+++ b/modules/bullet/btRayShape.cpp
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* btRayShape.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "btRayShape.h"
+#include "LinearMath/btAabbUtil2.h"
+#include "math/math_funcs.h"
+
+btRayShape::btRayShape(btScalar length)
+ : btConvexInternalShape(),
+ m_shapeAxis(0, 0, 1) {
+ m_shapeType = CUSTOM_CONVEX_SHAPE_TYPE;
+ setLength(length);
+}
+
+btRayShape::~btRayShape() {
+}
+
+void btRayShape::setLength(btScalar p_length) {
+
+ m_length = p_length;
+ reload_cache();
+}
+
+btVector3 btRayShape::localGetSupportingVertex(const btVector3 &vec) const {
+ return localGetSupportingVertexWithoutMargin(vec) + (m_shapeAxis * m_collisionMargin);
+}
+
+btVector3 btRayShape::localGetSupportingVertexWithoutMargin(const btVector3 &vec) const {
+ if (vec.z() > 0)
+ return m_shapeAxis * m_cacheScaledLength;
+ else
+ return btVector3(0, 0, 0);
+}
+
+void btRayShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3 *vectors, btVector3 *supportVerticesOut, int numVectors) const {
+ for (int i = 0; i < numVectors; ++i) {
+ supportVerticesOut[i] = localGetSupportingVertexWithoutMargin(vectors[i]);
+ }
+}
+
+void btRayShape::getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const {
+#define MARGIN_BROADPHASE 0.1
+ btVector3 localAabbMin(0, 0, 0);
+ btVector3 localAabbMax(m_shapeAxis * m_length);
+ btTransformAabb(localAabbMin, localAabbMax, MARGIN_BROADPHASE, t, aabbMin, aabbMax);
+}
+
+void btRayShape::calculateLocalInertia(btScalar mass, btVector3 &inertia) const {
+ inertia.setZero();
+}
+
+int btRayShape::getNumPreferredPenetrationDirections() const {
+ return 0;
+}
+
+void btRayShape::getPreferredPenetrationDirection(int index, btVector3 &penetrationVector) const {
+ penetrationVector.setZero();
+}
+
+void btRayShape::reload_cache() {
+
+ m_cacheScaledLength = m_length * m_localScaling[2] + m_collisionMargin;
+
+ m_cacheSupportPoint.setIdentity();
+ m_cacheSupportPoint.setOrigin(m_shapeAxis * m_cacheScaledLength);
+}
diff --git a/modules/bullet/btRayShape.h b/modules/bullet/btRayShape.h
new file mode 100644
index 0000000000..1b63fb477c
--- /dev/null
+++ b/modules/bullet/btRayShape.h
@@ -0,0 +1,87 @@
+/*************************************************************************/
+/* btRayShape.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/// IMPORTANT The class name and filename was created by following Bullet writing rules for an easy (eventually ) porting to bullet
+/// This shape is a custom shape that is not present to Bullet physics engine
+#ifndef BTRAYSHAPE_H
+#define BTRAYSHAPE_H
+
+#include "BulletCollision/CollisionShapes/btConvexInternalShape.h"
+
+/// Ray shape around z axis
+ATTRIBUTE_ALIGNED16(class)
+btRayShape : public btConvexInternalShape {
+
+ btScalar m_length;
+ /// The default axis is the z
+ btVector3 m_shapeAxis;
+
+ btTransform m_cacheSupportPoint;
+ btScalar m_cacheScaledLength;
+
+public:
+ BT_DECLARE_ALIGNED_ALLOCATOR();
+
+ btRayShape(btScalar length);
+ virtual ~btRayShape();
+
+ void setLength(btScalar p_length);
+ btScalar getLength() const { return m_length; }
+
+ const btTransform &getSupportPoint() const { return m_cacheSupportPoint; }
+ const btScalar &getScaledLength() const { return m_cacheScaledLength; }
+
+ virtual btVector3 localGetSupportingVertex(const btVector3 &vec) const;
+#ifndef __SPU__
+ virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3 &vec) const;
+#endif //#ifndef __SPU__
+
+ virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3 *vectors, btVector3 *supportVerticesOut, int numVectors) const;
+
+ ///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t.
+ virtual void getAabb(const btTransform &t, btVector3 &aabbMin, btVector3 &aabbMax) const;
+
+#ifndef __SPU__
+ virtual void calculateLocalInertia(btScalar mass, btVector3 & inertia) const;
+
+ virtual const char *getName() const {
+ return "RayZ";
+ }
+#endif //__SPU__
+
+ virtual int getNumPreferredPenetrationDirections() const;
+ virtual void getPreferredPenetrationDirection(int index, btVector3 &penetrationVector) const;
+
+private:
+ void reload_cache();
+};
+
+#endif // BTRAYSHAPE_H
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
new file mode 100644
index 0000000000..96875924a5
--- /dev/null
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -0,0 +1,1342 @@
+/*************************************************************************/
+/* bullet_physics_server.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "bullet_physics_server.h"
+#include "LinearMath/btVector3.h"
+#include "bullet_utilities.h"
+#include "class_db.h"
+#include "cone_twist_joint_bullet.h"
+#include "core/error_macros.h"
+#include "core/ustring.h"
+#include "generic_6dof_joint_bullet.h"
+#include "hinge_joint_bullet.h"
+#include "pin_joint_bullet.h"
+#include "shape_bullet.h"
+#include "slider_joint_bullet.h"
+#include <assert.h>
+
+#define CreateThenReturnRID(owner, ridData) \
+ RID rid = owner.make_rid(ridData); \
+ ridData->set_self(rid); \
+ ridData->_set_physics_server(this); \
+ return rid;
+
+// <--------------- Joint creation asserts
+/// Assert the body is assigned to a space
+#define JointAssertSpace(body, bIndex, ret) \
+ if (!body->get_space()) { \
+ ERR_PRINTS("Before create a joint the Body" + String(bIndex) + " must be added to a space!"); \
+ return ret; \
+ }
+
+/// Assert the two bodies of joint are in the same space
+#define JointAssertSameSpace(bodyA, bodyB, ret) \
+ if (bodyA->get_space() != bodyB->get_space()) { \
+ ERR_PRINT("In order to create a joint the Body_A and Body_B must be in the same space!"); \
+ return RID(); \
+ }
+
+#define AddJointToSpace(body, joint, disableCollisionsBetweenLinkedBodies) \
+ body->get_space()->add_constraint(joint, disableCollisionsBetweenLinkedBodies);
+// <--------------- Joint creation asserts
+
+btEmptyShape *BulletPhysicsServer::emptyShape(ShapeBullet::create_shape_empty());
+
+btEmptyShape *BulletPhysicsServer::get_empty_shape() {
+ return emptyShape;
+}
+
+void BulletPhysicsServer::_bind_methods() {
+ //ClassDB::bind_method(D_METHOD("DoTest"), &BulletPhysicsServer::DoTest);
+}
+
+BulletPhysicsServer::BulletPhysicsServer()
+ : PhysicsServer(),
+ active(true),
+ active_spaces_count(0) {}
+
+BulletPhysicsServer::~BulletPhysicsServer() {}
+
+RID BulletPhysicsServer::shape_create(ShapeType p_shape) {
+ ShapeBullet *shape = NULL;
+
+ switch (p_shape) {
+ case SHAPE_PLANE: {
+
+ shape = bulletnew(PlaneShapeBullet);
+ } break;
+ case SHAPE_SPHERE: {
+
+ shape = bulletnew(SphereShapeBullet);
+ } break;
+ case SHAPE_BOX: {
+
+ shape = bulletnew(BoxShapeBullet);
+ } break;
+ case SHAPE_CAPSULE: {
+
+ shape = bulletnew(CapsuleShapeBullet);
+ } break;
+ case SHAPE_CONVEX_POLYGON: {
+
+ shape = bulletnew(ConvexPolygonShapeBullet);
+ } break;
+ case SHAPE_CONCAVE_POLYGON: {
+
+ shape = bulletnew(ConcavePolygonShapeBullet);
+ } break;
+ case SHAPE_HEIGHTMAP: {
+
+ shape = bulletnew(HeightMapShapeBullet);
+ } break;
+ case SHAPE_RAY: {
+ shape = bulletnew(RayShapeBullet);
+ } break;
+ case SHAPE_CUSTOM:
+ defaul:
+ ERR_FAIL_V(RID());
+ break;
+ }
+
+ CreateThenReturnRID(shape_owner, shape)
+}
+
+void BulletPhysicsServer::shape_set_data(RID p_shape, const Variant &p_data) {
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_data(p_data);
+}
+
+void BulletPhysicsServer::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) {
+ //WARN_PRINT("Bias not supported by Bullet physics engine");
+}
+
+PhysicsServer::ShapeType BulletPhysicsServer::shape_get_type(RID p_shape) const {
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND_V(!shape, PhysicsServer::SHAPE_CUSTOM);
+ return shape->get_type();
+}
+
+Variant BulletPhysicsServer::shape_get_data(RID p_shape) const {
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND_V(!shape, Variant());
+ return shape->get_data();
+}
+
+real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const {
+ //WARN_PRINT("Bias not supported by Bullet physics engine");
+ return 0.;
+}
+
+RID BulletPhysicsServer::space_create() {
+ SpaceBullet *space = bulletnew(SpaceBullet(false));
+ CreateThenReturnRID(space_owner, space);
+}
+
+void BulletPhysicsServer::space_set_active(RID p_space, bool p_active) {
+
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+
+ if (space_is_active(p_space) == p_active) {
+ return;
+ }
+
+ if (p_active) {
+ ++active_spaces_count;
+ active_spaces.push_back(space);
+ } else {
+ --active_spaces_count;
+ active_spaces.erase(space);
+ }
+}
+
+bool BulletPhysicsServer::space_is_active(RID p_space) const {
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space, false);
+
+ return -1 != active_spaces.find(space);
+}
+
+void BulletPhysicsServer::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+ space->set_param(p_param, p_value);
+}
+
+real_t BulletPhysicsServer::space_get_param(RID p_space, SpaceParameter p_param) const {
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+ return space->get_param(p_param);
+}
+
+PhysicsDirectSpaceState *BulletPhysicsServer::space_get_direct_state(RID p_space) {
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space, NULL);
+
+ return space->get_direct_state();
+}
+
+void BulletPhysicsServer::space_set_debug_contacts(RID p_space, int p_max_contacts) {
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+
+ space->set_debug_contacts(p_max_contacts);
+}
+
+Vector<Vector3> BulletPhysicsServer::space_get_contacts(RID p_space) const {
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space, Vector<Vector3>());
+
+ return space->get_debug_contacts();
+}
+
+int BulletPhysicsServer::space_get_contact_count(RID p_space) const {
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space, 0);
+
+ return space->get_debug_contact_count();
+}
+
+RID BulletPhysicsServer::area_create() {
+ AreaBullet *area = bulletnew(AreaBullet);
+ area->set_collision_layer(1);
+ area->set_collision_mask(1);
+ CreateThenReturnRID(area_owner, area)
+}
+
+void BulletPhysicsServer::area_set_space(RID p_area, RID p_space) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ SpaceBullet *space = NULL;
+ if (p_space.is_valid()) {
+ space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+ }
+ area->set_space(space);
+}
+
+RID BulletPhysicsServer::area_get_space(RID p_area) const {
+ AreaBullet *area = area_owner.get(p_area);
+ return area->get_space()->get_self();
+}
+
+void BulletPhysicsServer::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area)
+
+ area->set_spOv_mode(p_mode);
+}
+
+PhysicsServer::AreaSpaceOverrideMode BulletPhysicsServer::area_get_space_override_mode(RID p_area) const {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED);
+
+ return area->get_spOv_mode();
+}
+
+void BulletPhysicsServer::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ area->add_shape(shape, p_transform);
+}
+
+void BulletPhysicsServer::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ area->set_shape(p_shape_idx, shape);
+}
+
+void BulletPhysicsServer::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_shape_transform(p_shape_idx, p_transform);
+}
+
+int BulletPhysicsServer::area_get_shape_count(RID p_area) const {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, 0);
+
+ return area->get_shape_count();
+}
+
+RID BulletPhysicsServer::area_get_shape(RID p_area, int p_shape_idx) const {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, RID());
+
+ return area->get_shape(p_shape_idx)->get_self();
+}
+
+Transform BulletPhysicsServer::area_get_shape_transform(RID p_area, int p_shape_idx) const {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, Transform());
+
+ return area->get_shape_transform(p_shape_idx);
+}
+
+void BulletPhysicsServer::area_remove_shape(RID p_area, int p_shape_idx) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ return area->remove_shape(p_shape_idx);
+}
+
+void BulletPhysicsServer::area_clear_shapes(RID p_area) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ for (int i = area->get_shape_count(); 0 < i; --i)
+ area->remove_shape(0);
+}
+
+void BulletPhysicsServer::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_shape_disabled(p_shape_idx, p_disabled);
+}
+
+void BulletPhysicsServer::area_attach_object_instance_id(RID p_area, ObjectID p_ID) {
+ if (space_owner.owns(p_area)) {
+ return;
+ }
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_instance_id(p_ID);
+}
+
+ObjectID BulletPhysicsServer::area_get_object_instance_id(RID p_area) const {
+ if (space_owner.owns(p_area)) {
+ return 0;
+ }
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, ObjectID());
+ return area->get_instance_id();
+}
+
+void BulletPhysicsServer::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
+ if (space_owner.owns(p_area)) {
+ SpaceBullet *space = space_owner.get(p_area);
+ if (space) {
+ space->set_param(p_param, p_value);
+ }
+ } else {
+
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_param(p_param, p_value);
+ }
+}
+
+Variant BulletPhysicsServer::area_get_param(RID p_area, AreaParameter p_param) const {
+ if (space_owner.owns(p_area)) {
+ SpaceBullet *space = space_owner.get(p_area);
+ return space->get_param(p_param);
+ } else {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, Variant());
+
+ return area->get_param(p_param);
+ }
+}
+
+void BulletPhysicsServer::area_set_transform(RID p_area, const Transform &p_transform) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_transform(p_transform);
+}
+
+Transform BulletPhysicsServer::area_get_transform(RID p_area) const {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, Transform());
+ return area->get_transform();
+}
+
+void BulletPhysicsServer::area_set_collision_mask(RID p_area, uint32_t p_mask) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_collision_mask(p_mask);
+}
+
+void BulletPhysicsServer::area_set_collision_layer(RID p_area, uint32_t p_layer) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_collision_layer(p_layer);
+}
+
+void BulletPhysicsServer::area_set_monitorable(RID p_area, bool p_monitorable) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_monitorable(p_monitorable);
+}
+
+void BulletPhysicsServer::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+}
+
+void BulletPhysicsServer::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+
+ area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_receiver ? p_receiver->get_instance_id() : 0, p_method);
+}
+
+void BulletPhysicsServer::area_set_ray_pickable(RID p_area, bool p_enable) {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND(!area);
+ area->set_ray_pickable(p_enable);
+}
+
+bool BulletPhysicsServer::area_is_ray_pickable(RID p_area) const {
+ AreaBullet *area = area_owner.get(p_area);
+ ERR_FAIL_COND_V(!area, false);
+ return area->is_ray_pickable();
+}
+
+RID BulletPhysicsServer::body_create(BodyMode p_mode, bool p_init_sleeping) {
+ RigidBodyBullet *body = bulletnew(RigidBodyBullet);
+ body->set_mode(p_mode);
+ body->set_collision_layer(1);
+ body->set_collision_mask(1);
+ if (p_init_sleeping)
+ body->set_state(BODY_STATE_SLEEPING, p_init_sleeping);
+ CreateThenReturnRID(rigid_body_owner, body);
+}
+
+void BulletPhysicsServer::body_set_space(RID p_body, RID p_space) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ SpaceBullet *space = NULL;
+
+ if (p_space.is_valid()) {
+ space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (body->get_space() == space)
+ return; //pointles
+
+ body->set_space(space);
+}
+
+RID BulletPhysicsServer::body_get_space(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ SpaceBullet *space = body->get_space();
+ if (!space)
+ return RID();
+ return space->get_self();
+}
+
+void BulletPhysicsServer::body_set_mode(RID p_body, PhysicsServer::BodyMode p_mode) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_mode(p_mode);
+}
+
+PhysicsServer::BodyMode BulletPhysicsServer::body_get_mode(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
+ return body->get_mode();
+}
+
+void BulletPhysicsServer::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform) {
+
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ body->add_shape(shape, p_transform);
+}
+
+void BulletPhysicsServer::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND(!shape);
+
+ body->set_shape(p_shape_idx, shape);
+}
+
+void BulletPhysicsServer::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_shape_transform(p_shape_idx, p_transform);
+}
+
+int BulletPhysicsServer::body_get_shape_count(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+ return body->get_shape_count();
+}
+
+RID BulletPhysicsServer::body_get_shape(RID p_body, int p_shape_idx) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ ShapeBullet *shape = body->get_shape(p_shape_idx);
+ ERR_FAIL_COND_V(!shape, RID());
+
+ return shape->get_self();
+}
+
+Transform BulletPhysicsServer::body_get_shape_transform(RID p_body, int p_shape_idx) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, Transform());
+ return body->get_shape_transform(p_shape_idx);
+}
+
+void BulletPhysicsServer::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_shape_disabled(p_shape_idx, p_disabled);
+}
+
+void BulletPhysicsServer::body_remove_shape(RID p_body, int p_shape_idx) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_shape(p_shape_idx);
+}
+
+void BulletPhysicsServer::body_clear_shapes(RID p_body) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->remove_all_shapes();
+}
+
+void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, uint32_t p_ID) {
+ CollisionObjectBullet *body = get_collisin_object(p_body);
+ if (!body) {
+ body = soft_body_owner.get(p_body);
+ }
+ ERR_FAIL_COND(!body);
+
+ body->set_instance_id(p_ID);
+}
+
+uint32_t BulletPhysicsServer::body_get_object_instance_id(RID p_body) const {
+ CollisionObjectBullet *body = get_collisin_object(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_instance_id();
+}
+
+void BulletPhysicsServer::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_continuous_collision_detection(p_enable);
+}
+
+bool BulletPhysicsServer::body_is_continuous_collision_detection_enabled(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, false);
+
+ return body->is_continuous_collision_detection_enabled();
+}
+
+void BulletPhysicsServer::body_set_collision_layer(RID p_body, uint32_t p_layer) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_layer(p_layer);
+}
+
+uint32_t BulletPhysicsServer::body_get_collision_layer(RID p_body) const {
+ const RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_layer();
+}
+
+void BulletPhysicsServer::body_set_collision_mask(RID p_body, uint32_t p_mask) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_mask(p_mask);
+}
+
+uint32_t BulletPhysicsServer::body_get_collision_mask(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_mask();
+}
+
+void BulletPhysicsServer::body_set_user_flags(RID p_body, uint32_t p_flags) {
+ WARN_PRINT("This function si not currently supported by bullet and Godot");
+}
+
+uint32_t BulletPhysicsServer::body_get_user_flags(RID p_body) const {
+ WARN_PRINT("This function si not currently supported by bullet and Godot");
+ return 0;
+}
+
+void BulletPhysicsServer::body_set_param(RID p_body, BodyParameter p_param, float p_value) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_param(p_param, p_value);
+}
+
+float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_param(p_param);
+}
+
+void BulletPhysicsServer::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_state(p_state, p_variant);
+}
+
+Variant BulletPhysicsServer::body_get_state(RID p_body, BodyState p_state) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, Variant());
+
+ return body->get_state(p_state);
+}
+
+void BulletPhysicsServer::body_set_applied_force(RID p_body, const Vector3 &p_force) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_applied_force(p_force);
+}
+
+Vector3 BulletPhysicsServer::body_get_applied_force(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, Vector3());
+ return body->get_applied_force();
+}
+
+void BulletPhysicsServer::body_set_applied_torque(RID p_body, const Vector3 &p_torque) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_applied_torque(p_torque);
+}
+
+Vector3 BulletPhysicsServer::body_get_applied_torque(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, Vector3());
+
+ return body->get_applied_torque();
+}
+
+void BulletPhysicsServer::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->apply_impulse(p_pos, p_impulse);
+}
+
+void BulletPhysicsServer::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->apply_torque_impulse(p_impulse);
+}
+
+void BulletPhysicsServer::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ Vector3 v = body->get_linear_velocity();
+ Vector3 axis = p_axis_velocity.normalized();
+ v -= axis * axis.dot(v);
+ v += p_axis_velocity;
+ body->set_linear_velocity(v);
+}
+
+void BulletPhysicsServer::body_set_axis_lock(RID p_body, PhysicsServer::BodyAxisLock p_lock) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_axis_lock(p_lock);
+}
+
+PhysicsServer::BodyAxisLock BulletPhysicsServer::body_get_axis_lock(RID p_body) const {
+ const RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, BODY_AXIS_LOCK_DISABLED);
+ return body->get_axis_lock();
+}
+
+void BulletPhysicsServer::body_add_collision_exception(RID p_body, RID p_body_b) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ RigidBodyBullet *other_body = rigid_body_owner.get(p_body_b);
+ ERR_FAIL_COND(!other_body);
+
+ body->add_collision_exception(other_body);
+}
+
+void BulletPhysicsServer::body_remove_collision_exception(RID p_body, RID p_body_b) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ RigidBodyBullet *other_body = rigid_body_owner.get(p_body_b);
+ ERR_FAIL_COND(!other_body);
+
+ body->remove_collision_exception(other_body);
+}
+
+void BulletPhysicsServer::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ for (int i = 0; i < body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(body->get_exceptions()[i]);
+ }
+}
+
+void BulletPhysicsServer::body_set_max_contacts_reported(RID p_body, int p_contacts) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_max_collisions_detection(p_contacts);
+}
+
+int BulletPhysicsServer::body_get_max_contacts_reported(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_max_collisions_detection();
+}
+
+void BulletPhysicsServer::body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold) {
+ WARN_PRINT("Not supported by bullet and even Godot");
+}
+
+float BulletPhysicsServer::body_get_contacts_reported_depth_threshold(RID p_body) const {
+ WARN_PRINT("Not supported by bullet and even Godot");
+ return 0.;
+}
+
+void BulletPhysicsServer::body_set_omit_force_integration(RID p_body, bool p_omit) {
+ WARN_PRINT("Not supported by bullet");
+}
+
+bool BulletPhysicsServer::body_is_omitting_force_integration(RID p_body) const {
+ WARN_PRINT("Not supported by bullet");
+ return false;
+}
+
+void BulletPhysicsServer::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_force_integration_callback(p_receiver->get_instance_id(), p_method, p_udata);
+}
+
+void BulletPhysicsServer::body_set_ray_pickable(RID p_body, bool p_enable) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_ray_pickable(p_enable);
+}
+
+bool BulletPhysicsServer::body_is_ray_pickable(RID p_body) const {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ return body->is_ray_pickable();
+}
+
+PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, NULL);
+ return BulletPhysicsDirectBodyState::get_singleton(body);
+}
+
+bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, float p_margin, MotionResult *r_result) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ ERR_FAIL_COND_V(!body->get_space(), false);
+
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result);
+}
+
+RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) {
+ SoftBodyBullet *body = bulletnew(SoftBodyBullet);
+ body->set_collision_layer(1);
+ body->set_collision_mask(1);
+ if (p_init_sleeping)
+ body->set_activation_state(false);
+ CreateThenReturnRID(soft_body_owner, body);
+}
+
+void BulletPhysicsServer::soft_body_set_space(RID p_body, RID p_space) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ SpaceBullet *space = NULL;
+
+ if (p_space.is_valid()) {
+ space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+ }
+
+ if (body->get_space() == space)
+ return; //pointles
+
+ body->set_space(space);
+}
+
+RID BulletPhysicsServer::soft_body_get_space(RID p_body) const {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, RID());
+
+ SpaceBullet *space = body->get_space();
+ if (!space)
+ return RID();
+ return space->get_self();
+}
+
+void BulletPhysicsServer::soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_trimesh_body_shape(p_indices, p_vertices, p_triangles_num);
+}
+
+void BulletPhysicsServer::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_layer(p_layer);
+}
+
+uint32_t BulletPhysicsServer::soft_body_get_collision_layer(RID p_body) const {
+ const SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_layer();
+}
+
+void BulletPhysicsServer::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_mask(p_mask);
+}
+
+uint32_t BulletPhysicsServer::soft_body_get_collision_mask(RID p_body) const {
+ const SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_mask();
+}
+
+void BulletPhysicsServer::soft_body_add_collision_exception(RID p_body, RID p_body_b) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ CollisionObjectBullet *other_body = rigid_body_owner.get(p_body_b);
+ if (!other_body) {
+ other_body = soft_body_owner.get(p_body_b);
+ }
+ ERR_FAIL_COND(!other_body);
+
+ body->add_collision_exception(other_body);
+}
+
+void BulletPhysicsServer::soft_body_remove_collision_exception(RID p_body, RID p_body_b) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ CollisionObjectBullet *other_body = rigid_body_owner.get(p_body_b);
+ if (!other_body) {
+ other_body = soft_body_owner.get(p_body_b);
+ }
+ ERR_FAIL_COND(!other_body);
+
+ body->remove_collision_exception(other_body);
+}
+
+void BulletPhysicsServer::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ for (int i = 0; i < body->get_exceptions().size(); i++) {
+ p_exceptions->push_back(body->get_exceptions()[i]);
+ }
+}
+
+void BulletPhysicsServer::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
+ print_line("TODO MUST BE IMPLEMENTED");
+}
+
+Variant BulletPhysicsServer::soft_body_get_state(RID p_body, BodyState p_state) const {
+ print_line("TODO MUST BE IMPLEMENTED");
+ return Variant();
+}
+
+void BulletPhysicsServer::soft_body_set_transform(RID p_body, const Transform &p_transform) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_transform(p_transform);
+}
+
+Transform BulletPhysicsServer::soft_body_get_transform(RID p_body) const {
+ const SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, Transform());
+
+ return body->get_transform();
+}
+
+void BulletPhysicsServer::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND(!body);
+ body->set_ray_pickable(p_enable);
+}
+
+bool BulletPhysicsServer::soft_body_is_ray_pickable(RID p_body) const {
+ SoftBodyBullet *body = soft_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, false);
+ return body->is_ray_pickable();
+}
+
+PhysicsServer::JointType BulletPhysicsServer::joint_get_type(RID p_joint) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, JOINT_PIN);
+ return joint->get_type();
+}
+
+void BulletPhysicsServer::joint_set_solver_priority(RID p_joint, int p_priority) {
+ //WARN_PRINTS("Joint priority not supported by bullet");
+}
+
+int BulletPhysicsServer::joint_get_solver_priority(RID p_joint) const {
+ //WARN_PRINTS("Joint priority not supported by bullet");
+ return 0;
+}
+
+RID BulletPhysicsServer::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
+ RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+
+ JointAssertSpace(body_A, "A", RID());
+
+ RigidBodyBullet *body_B = NULL;
+ if (p_body_B.is_valid()) {
+ body_B = rigid_body_owner.get(p_body_B);
+ JointAssertSpace(body_B, "B", RID());
+ JointAssertSameSpace(body_A, body_B, RID());
+ }
+
+ ERR_FAIL_COND_V(body_A == body_B, RID());
+
+ JointBullet *joint = bulletnew(PinJointBullet(body_A, p_local_A, body_B, p_local_B));
+ AddJointToSpace(body_A, joint, true);
+
+ CreateThenReturnRID(joint_owner, joint);
+}
+
+void BulletPhysicsServer::pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
+ PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
+ pin_joint->set_param(p_param, p_value);
+}
+
+float BulletPhysicsServer::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0);
+ PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
+ return pin_joint->get_param(p_param);
+}
+
+void BulletPhysicsServer::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
+ PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
+ pin_joint->setPivotInA(p_A);
+}
+
+Vector3 BulletPhysicsServer::pin_joint_get_local_a(RID p_joint) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, Vector3());
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
+ PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
+ return pin_joint->getPivotInA();
+}
+
+void BulletPhysicsServer::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
+ PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
+ pin_joint->setPivotInB(p_B);
+}
+
+Vector3 BulletPhysicsServer::pin_joint_get_local_b(RID p_joint) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, Vector3());
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
+ PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
+ return pin_joint->getPivotInB();
+}
+
+RID BulletPhysicsServer::joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) {
+ RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+ JointAssertSpace(body_A, "A", RID());
+
+ RigidBodyBullet *body_B = NULL;
+ if (p_body_B.is_valid()) {
+ body_B = rigid_body_owner.get(p_body_B);
+ JointAssertSpace(body_B, "B", RID());
+ JointAssertSameSpace(body_A, body_B, RID());
+ }
+
+ ERR_FAIL_COND_V(body_A == body_B, RID());
+
+ JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_hinge_A, p_hinge_B));
+ AddJointToSpace(body_A, joint, true);
+
+ CreateThenReturnRID(joint_owner, joint);
+}
+
+RID BulletPhysicsServer::joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) {
+ RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+ JointAssertSpace(body_A, "A", RID());
+
+ RigidBodyBullet *body_B = NULL;
+ if (p_body_B.is_valid()) {
+ body_B = rigid_body_owner.get(p_body_B);
+ JointAssertSpace(body_B, "B", RID());
+ JointAssertSameSpace(body_A, body_B, RID());
+ }
+
+ ERR_FAIL_COND_V(body_A == body_B, RID());
+
+ JointBullet *joint = bulletnew(HingeJointBullet(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B));
+ AddJointToSpace(body_A, joint, true);
+
+ CreateThenReturnRID(joint_owner, joint);
+}
+
+void BulletPhysicsServer::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
+ HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
+ hinge_joint->set_param(p_param, p_value);
+}
+
+float BulletPhysicsServer::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0);
+ HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
+ return hinge_joint->get_param(p_param);
+}
+
+void BulletPhysicsServer::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
+ HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
+ hinge_joint->set_flag(p_flag, p_value);
+}
+
+bool BulletPhysicsServer::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, false);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false);
+ HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
+ return hinge_joint->get_flag(p_flag);
+}
+
+RID BulletPhysicsServer::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+ RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+ JointAssertSpace(body_A, "A", RID());
+
+ RigidBodyBullet *body_B = NULL;
+ if (p_body_B.is_valid()) {
+ body_B = rigid_body_owner.get(p_body_B);
+ JointAssertSpace(body_B, "B", RID());
+ JointAssertSameSpace(body_A, body_B, RID());
+ }
+
+ ERR_FAIL_COND_V(body_A == body_B, RID());
+
+ JointBullet *joint = bulletnew(SliderJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B));
+ AddJointToSpace(body_A, joint, true);
+
+ CreateThenReturnRID(joint_owner, joint);
+}
+
+void BulletPhysicsServer::slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER);
+ SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint);
+ slider_joint->set_param(p_param, p_value);
+}
+
+float BulletPhysicsServer::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, 0);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_SLIDER, 0);
+ SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint);
+ return slider_joint->get_param(p_param);
+}
+
+RID BulletPhysicsServer::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+ RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+ JointAssertSpace(body_A, "A", RID());
+
+ RigidBodyBullet *body_B = NULL;
+ if (p_body_B.is_valid()) {
+ body_B = rigid_body_owner.get(p_body_B);
+ JointAssertSpace(body_B, "B", RID());
+ JointAssertSameSpace(body_A, body_B, RID());
+ }
+
+ JointBullet *joint = bulletnew(ConeTwistJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B));
+ AddJointToSpace(body_A, joint, true);
+
+ CreateThenReturnRID(joint_owner, joint);
+}
+
+void BulletPhysicsServer::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!joint);
+ ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST);
+ ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint);
+ coneTwist_joint->set_param(p_param, p_value);
+}
+
+float BulletPhysicsServer::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, 0.);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0.);
+ ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint);
+ return coneTwist_joint->get_param(p_param);
+}
+
+RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) {
+ RigidBodyBullet *body_A = rigid_body_owner.get(p_body_A);
+ ERR_FAIL_COND_V(!body_A, RID());
+ JointAssertSpace(body_A, "A", RID());
+
+ RigidBodyBullet *body_B = NULL;
+ if (p_body_B.is_valid()) {
+ body_B = rigid_body_owner.get(p_body_B);
+ JointAssertSpace(body_B, "B", RID());
+ JointAssertSameSpace(body_A, body_B, RID());
+ }
+
+ ERR_FAIL_COND_V(body_A == body_B, RID());
+
+ JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B, true));
+ AddJointToSpace(body_A, joint, true);
+
+ CreateThenReturnRID(joint_owner, joint);
+}
+
+void BulletPhysicsServer::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) {
+ JointBullet *joint = joint_owner.get(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_param(p_axis, p_param, p_value);
+}
+
+float BulletPhysicsServer::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
+ JointBullet *joint = joint_owner.get(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_param(p_axis, p_param);
+}
+
+void BulletPhysicsServer::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) {
+ JointBullet *joint = joint_owner.get(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_flag(p_axis, p_flag, p_enable);
+}
+
+bool BulletPhysicsServer::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) {
+ JointBullet *joint = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!joint, false);
+ ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false);
+ Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
+ return generic_6dof_joint->get_flag(p_axis, p_flag);
+}
+
+void BulletPhysicsServer::free(RID p_rid) {
+ if (shape_owner.owns(p_rid)) {
+
+ ShapeBullet *shape = shape_owner.get(p_rid);
+
+ // Notify the shape is configured
+ for (Map<ShapeOwnerBullet *, int>::Element *element = shape->get_owners().front(); element; element = element->next()) {
+ static_cast<ShapeOwnerBullet *>(element->key())->remove_shape(shape);
+ }
+
+ shape_owner.free(p_rid);
+ bulletdelete(shape);
+ } else if (rigid_body_owner.owns(p_rid)) {
+
+ RigidBodyBullet *body = rigid_body_owner.get(p_rid);
+
+ body->set_space(NULL);
+
+ body->remove_all_shapes(true);
+
+ rigid_body_owner.free(p_rid);
+ bulletdelete(body);
+
+ } else if (soft_body_owner.owns(p_rid)) {
+
+ SoftBodyBullet *body = soft_body_owner.get(p_rid);
+
+ body->set_space(NULL);
+
+ soft_body_owner.free(p_rid);
+ bulletdelete(body);
+
+ } else if (area_owner.owns(p_rid)) {
+
+ AreaBullet *area = area_owner.get(p_rid);
+
+ area->set_space(NULL);
+
+ area->remove_all_shapes(true);
+
+ area_owner.free(p_rid);
+ bulletdelete(area);
+
+ } else if (joint_owner.owns(p_rid)) {
+
+ JointBullet *joint = joint_owner.get(p_rid);
+ joint->destroy_internal_constraint();
+ joint_owner.free(p_rid);
+ bulletdelete(joint);
+
+ } else if (space_owner.owns(p_rid)) {
+
+ SpaceBullet *space = space_owner.get(p_rid);
+
+ space->remove_all_collision_objects();
+
+ space_set_active(p_rid, false);
+ space_owner.free(p_rid);
+ bulletdelete(space);
+ } else {
+
+ ERR_EXPLAIN("Invalid ID");
+ ERR_FAIL();
+ }
+}
+
+void BulletPhysicsServer::init() {
+ BulletPhysicsDirectBodyState::initSingleton();
+}
+
+void BulletPhysicsServer::step(float p_deltaTime) {
+ if (!active)
+ return;
+
+ BulletPhysicsDirectBodyState::singleton_setDeltaTime(p_deltaTime);
+
+ for (int i = 0; i < active_spaces_count; ++i) {
+
+ active_spaces[i]->step(p_deltaTime);
+ }
+}
+
+void BulletPhysicsServer::sync() {
+}
+
+void BulletPhysicsServer::flush_queries() {
+}
+
+void BulletPhysicsServer::finish() {
+ BulletPhysicsDirectBodyState::destroySingleton();
+}
+
+int BulletPhysicsServer::get_process_info(ProcessInfo p_info) {
+ return 0;
+}
+
+CollisionObjectBullet *BulletPhysicsServer::get_collisin_object(RID p_object) const {
+ if (rigid_body_owner.owns(p_object)) {
+ return rigid_body_owner.getornull(p_object);
+ }
+ if (area_owner.owns(p_object)) {
+ return area_owner.getornull(p_object);
+ }
+ if (soft_body_owner.owns(p_object)) {
+ return soft_body_owner.getornull(p_object);
+ }
+ return NULL;
+}
+
+RigidCollisionObjectBullet *BulletPhysicsServer::get_rigid_collisin_object(RID p_object) const {
+ if (rigid_body_owner.owns(p_object)) {
+ return rigid_body_owner.getornull(p_object);
+ }
+ if (area_owner.owns(p_object)) {
+ return area_owner.getornull(p_object);
+ }
+ return NULL;
+}
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
new file mode 100644
index 0000000000..04d9d89594
--- /dev/null
+++ b/modules/bullet/bullet_physics_server.h
@@ -0,0 +1,359 @@
+/*************************************************************************/
+/* bullet_physics_server.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BULLET_PHYSICS_SERVER_H
+#define BULLET_PHYSICS_SERVER_H
+
+#include "area_bullet.h"
+#include "joint_bullet.h"
+#include "rid.h"
+#include "rigid_body_bullet.h"
+#include "servers/physics_server.h"
+#include "shape_bullet.h"
+#include "soft_body_bullet.h"
+#include "space_bullet.h"
+
+class BulletPhysicsServer : public PhysicsServer {
+ GDCLASS(BulletPhysicsServer, PhysicsServer)
+
+ friend class BulletPhysicsDirectSpaceState;
+
+ bool active;
+ char active_spaces_count;
+ Vector<SpaceBullet *> active_spaces;
+
+ mutable RID_Owner<SpaceBullet> space_owner;
+ mutable RID_Owner<ShapeBullet> shape_owner;
+ mutable RID_Owner<AreaBullet> area_owner;
+ mutable RID_Owner<RigidBodyBullet> rigid_body_owner;
+ mutable RID_Owner<SoftBodyBullet> soft_body_owner;
+ mutable RID_Owner<JointBullet> joint_owner;
+
+private:
+ /// This is used when a collision shape is not active, so the bullet compound shapes index are always sync with godot index
+ static btEmptyShape *emptyShape;
+
+public:
+ static btEmptyShape *get_empty_shape();
+
+protected:
+ static void _bind_methods();
+
+public:
+ BulletPhysicsServer();
+ ~BulletPhysicsServer();
+
+ _FORCE_INLINE_ RID_Owner<SpaceBullet> *get_space_owner() {
+ return &space_owner;
+ }
+ _FORCE_INLINE_ RID_Owner<ShapeBullet> *get_shape_owner() {
+ return &shape_owner;
+ }
+ _FORCE_INLINE_ RID_Owner<AreaBullet> *get_area_owner() {
+ return &area_owner;
+ }
+ _FORCE_INLINE_ RID_Owner<RigidBodyBullet> *get_rigid_body_owner() {
+ return &rigid_body_owner;
+ }
+ _FORCE_INLINE_ RID_Owner<SoftBodyBullet> *get_soft_body_owner() {
+ return &soft_body_owner;
+ }
+ _FORCE_INLINE_ RID_Owner<JointBullet> *get_joint_owner() {
+ return &joint_owner;
+ }
+
+ /* SHAPE API */
+ virtual RID shape_create(ShapeType p_shape);
+ virtual void shape_set_data(RID p_shape, const Variant &p_data);
+ virtual ShapeType shape_get_type(RID p_shape) const;
+ virtual Variant shape_get_data(RID p_shape) const;
+
+ /// Not supported
+ virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias);
+ /// Not supported
+ virtual real_t shape_get_custom_solver_bias(RID p_shape) const;
+
+ /* SPACE API */
+
+ virtual RID space_create();
+ virtual void space_set_active(RID p_space, bool p_active);
+ virtual bool space_is_active(RID p_space) const;
+
+ /// Not supported
+ virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value);
+ /// Not supported
+ virtual real_t space_get_param(RID p_space, SpaceParameter p_param) const;
+
+ virtual PhysicsDirectSpaceState *space_get_direct_state(RID p_space);
+
+ virtual void space_set_debug_contacts(RID p_space, int p_max_contacts);
+ virtual Vector<Vector3> space_get_contacts(RID p_space) const;
+ virtual int space_get_contact_count(RID p_space) const;
+
+ /* AREA API */
+
+ /// Bullet Physics Engine not support "Area", this must be handled by the game developer in another way.
+ /// Since godot Physics use the concept of area even to define the main world, the API area_set_param is used to set initial physics world information.
+ /// The API area_set_param is a bit hacky, and allow Godot to set some parameters on Bullet's world, a different use print a warning to console.
+ /// All other APIs returns a warning message if used
+
+ virtual RID area_create();
+
+ virtual void area_set_space(RID p_area, RID p_space);
+
+ virtual RID area_get_space(RID p_area) const;
+
+ virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode);
+ virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const;
+
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform());
+ virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
+ virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform);
+ virtual int area_get_shape_count(RID p_area) const;
+ virtual RID area_get_shape(RID p_area, int p_shape_idx) const;
+ virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const;
+ virtual void area_remove_shape(RID p_area, int p_shape_idx);
+ virtual void area_clear_shapes(RID p_area);
+ virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled);
+ virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID);
+ virtual ObjectID area_get_object_instance_id(RID p_area) const;
+
+ /// If you pass as p_area the SpaceBullet you can set some parameters as specified below
+ /// AREA_PARAM_GRAVITY
+ /// AREA_PARAM_GRAVITY_VECTOR
+ /// Otherwise you can set area parameters
+ virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value);
+ virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const;
+
+ virtual void area_set_transform(RID p_area, const Transform &p_transform);
+ virtual Transform area_get_transform(RID p_area) const;
+
+ virtual void area_set_collision_mask(RID p_area, uint32_t p_mask);
+ virtual void area_set_collision_layer(RID p_area, uint32_t p_layer);
+
+ virtual void area_set_monitorable(RID p_area, bool p_monitorable);
+ virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
+ virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method);
+ virtual void area_set_ray_pickable(RID p_area, bool p_enable);
+ virtual bool area_is_ray_pickable(RID p_area) const;
+
+ /* RIGID BODY API */
+
+ virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false);
+
+ virtual void body_set_space(RID p_body, RID p_space);
+ virtual RID body_get_space(RID p_body) const;
+
+ virtual void body_set_mode(RID p_body, BodyMode p_mode);
+ virtual BodyMode body_get_mode(RID p_body) const;
+
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform());
+ // Not supported, Please remove and add new shape
+ virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
+ virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform);
+
+ virtual int body_get_shape_count(RID p_body) const;
+ virtual RID body_get_shape(RID p_body, int p_shape_idx) const;
+ virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const;
+
+ virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled);
+
+ virtual void body_remove_shape(RID p_body, int p_shape_idx);
+ virtual void body_clear_shapes(RID p_body);
+
+ // Used for Rigid and Soft Bodies
+ virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID);
+ virtual uint32_t body_get_object_instance_id(RID p_body) const;
+
+ virtual void body_set_enable_continuous_collision_detection(RID p_body, bool p_enable);
+ virtual bool body_is_continuous_collision_detection_enabled(RID p_body) const;
+
+ virtual void body_set_collision_layer(RID p_body, uint32_t p_layer);
+ virtual uint32_t body_get_collision_layer(RID p_body) const;
+
+ virtual void body_set_collision_mask(RID p_body, uint32_t p_mask);
+ virtual uint32_t body_get_collision_mask(RID p_body) const;
+
+ /// This is not supported by physics server
+ virtual void body_set_user_flags(RID p_body, uint32_t p_flags);
+ /// This is not supported by physics server
+ virtual uint32_t body_get_user_flags(RID p_body) const;
+
+ virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value);
+ virtual float body_get_param(RID p_body, BodyParameter p_param) const;
+
+ virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
+ virtual Variant body_get_state(RID p_body, BodyState p_state) const;
+
+ virtual void body_set_applied_force(RID p_body, const Vector3 &p_force);
+ virtual Vector3 body_get_applied_force(RID p_body) const;
+
+ virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque);
+ virtual Vector3 body_get_applied_torque(RID p_body) const;
+
+ virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse);
+ virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse);
+ virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity);
+
+ virtual void body_set_axis_lock(RID p_body, BodyAxisLock p_lock);
+ virtual BodyAxisLock body_get_axis_lock(RID p_body) const;
+
+ virtual void body_add_collision_exception(RID p_body, RID p_body_b);
+ virtual void body_remove_collision_exception(RID p_body, RID p_body_b);
+ virtual void body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions);
+
+ virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
+ virtual int body_get_max_contacts_reported(RID p_body) const;
+
+ virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_treshold);
+ virtual float body_get_contacts_reported_depth_threshold(RID p_body) const;
+
+ virtual void body_set_omit_force_integration(RID p_body, bool p_omit);
+ virtual bool body_is_omitting_force_integration(RID p_body) const;
+
+ virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant());
+
+ virtual void body_set_ray_pickable(RID p_body, bool p_enable);
+ virtual bool body_is_ray_pickable(RID p_body) const;
+
+ // this function only works on physics process, errors and returns null otherwise
+ virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body);
+
+ virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, float p_margin = 0.001, MotionResult *r_result = NULL);
+
+ /* SOFT BODY API */
+
+ virtual RID soft_body_create(bool p_init_sleeping = false);
+
+ virtual void soft_body_set_space(RID p_body, RID p_space);
+ virtual RID soft_body_get_space(RID p_body) const;
+
+ virtual void soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num);
+
+ virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer);
+ virtual uint32_t soft_body_get_collision_layer(RID p_body) const;
+
+ virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask);
+ virtual uint32_t soft_body_get_collision_mask(RID p_body) const;
+
+ virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b);
+ virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b);
+ virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions);
+
+ virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
+ virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const;
+
+ virtual void soft_body_set_transform(RID p_body, const Transform &p_transform);
+ virtual Transform soft_body_get_transform(RID p_body) const;
+
+ virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable);
+ virtual bool soft_body_is_ray_pickable(RID p_body) const;
+
+ /* JOINT API */
+
+ virtual JointType joint_get_type(RID p_joint) const;
+
+ virtual void joint_set_solver_priority(RID p_joint, int p_priority);
+ virtual int joint_get_solver_priority(RID p_joint) const;
+
+ virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B);
+
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value);
+ virtual float pin_joint_get_param(RID p_joint, PinJointParam p_param) const;
+
+ virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A);
+ virtual Vector3 pin_joint_get_local_a(RID p_joint) const;
+
+ virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B);
+ virtual Vector3 pin_joint_get_local_b(RID p_joint) const;
+
+ virtual RID joint_create_hinge(RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B);
+ virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B);
+
+ virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value);
+ virtual float hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const;
+
+ virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value);
+ virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const;
+
+ /// 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);
+
+ virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value);
+ virtual float slider_joint_get_param(RID p_joint, SliderJointParam p_param) const;
+
+ /// 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);
+
+ virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value);
+ virtual float cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const;
+
+ /// 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);
+
+ virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value);
+ virtual float generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param);
+
+ virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable);
+ virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag);
+
+ /* MISC */
+
+ virtual void free(RID p_rid);
+
+ virtual void set_active(bool p_active) {
+ active = p_active;
+ }
+
+ static bool singleton_isActive() {
+ return static_cast<BulletPhysicsServer *>(get_singleton())->active;
+ }
+
+ bool isActive() {
+ return active;
+ }
+
+ virtual void init();
+ virtual void step(float p_deltaTime);
+ virtual void sync();
+ virtual void flush_queries();
+ virtual void finish();
+
+ virtual int get_process_info(ProcessInfo p_info);
+
+ CollisionObjectBullet *get_collisin_object(RID p_object) const;
+ RigidCollisionObjectBullet *get_rigid_collisin_object(RID p_object) const;
+
+ /// Internal APIs
+public:
+};
+
+#endif
diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp
new file mode 100644
index 0000000000..5010197a78
--- /dev/null
+++ b/modules/bullet/bullet_types_converter.cpp
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* bullet_types_converter.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#pragma once
+
+#include "bullet_types_converter.h"
+
+// ++ BULLET to GODOT ++++++++++
+void B_TO_G(btVector3 const &inVal, Vector3 &outVal) {
+ outVal[0] = inVal[0];
+ outVal[1] = inVal[1];
+ outVal[2] = inVal[2];
+}
+
+void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal) {
+ outVal[0] = inVal[0] != 0. ? 1. / inVal[0] : 0.;
+ outVal[1] = inVal[1] != 0. ? 1. / inVal[1] : 0.;
+ outVal[2] = inVal[2] != 0. ? 1. / inVal[2] : 0.;
+}
+
+void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) {
+ B_TO_G(inVal[0], outVal[0]);
+ B_TO_G(inVal[1], outVal[1]);
+ B_TO_G(inVal[2], outVal[2]);
+}
+
+void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) {
+ INVERT_B_TO_G(inVal[0], outVal[0]);
+ INVERT_B_TO_G(inVal[1], outVal[1]);
+ INVERT_B_TO_G(inVal[2], outVal[2]);
+}
+
+void B_TO_G(btTransform const &inVal, Transform &outVal) {
+ B_TO_G(inVal.getBasis(), outVal.basis);
+ B_TO_G(inVal.getOrigin(), outVal.origin);
+}
+
+// ++ GODOT to BULLET ++++++++++
+void G_TO_B(Vector3 const &inVal, btVector3 &outVal) {
+ outVal[0] = inVal[0];
+ outVal[1] = inVal[1];
+ outVal[2] = inVal[2];
+}
+
+void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal) {
+ outVal[0] = inVal[0] != 0. ? 1. / inVal[0] : 0.;
+ outVal[1] = inVal[1] != 0. ? 1. / inVal[1] : 0.;
+ outVal[2] = inVal[2] != 0. ? 1. / inVal[2] : 0.;
+}
+
+void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) {
+ G_TO_B(inVal[0], outVal[0]);
+ G_TO_B(inVal[1], outVal[1]);
+ G_TO_B(inVal[2], outVal[2]);
+}
+
+void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) {
+ INVERT_G_TO_B(inVal[0], outVal[0]);
+ INVERT_G_TO_B(inVal[1], outVal[1]);
+ INVERT_G_TO_B(inVal[2], outVal[2]);
+}
+
+void G_TO_B(Transform const &inVal, btTransform &outVal) {
+ G_TO_B(inVal.basis, outVal.getBasis());
+ G_TO_B(inVal.origin, outVal.getOrigin());
+}
diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h
new file mode 100644
index 0000000000..ed6a349382
--- /dev/null
+++ b/modules/bullet/bullet_types_converter.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* bullet_types_converter.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BULLET_TYPES_CONVERTER_H
+#define BULLET_TYPES_CONVERTER_H
+
+#include "LinearMath/btMatrix3x3.h"
+#include "LinearMath/btTransform.h"
+#include "LinearMath/btVector3.h"
+#include "core/math/matrix3.h"
+#include "core/math/transform.h"
+#include "core/math/vector3.h"
+#include "core/typedefs.h"
+
+// Bullet to Godot
+extern void B_TO_G(btVector3 const &inVal, Vector3 &outVal);
+extern void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal);
+extern void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal);
+extern void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal);
+extern void B_TO_G(btTransform const &inVal, Transform &outVal);
+
+// Godot TO Bullet
+extern void G_TO_B(Vector3 const &inVal, btVector3 &outVal);
+extern void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal);
+extern void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal);
+extern void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal);
+extern void G_TO_B(Transform const &inVal, btTransform &outVal);
+
+#endif
diff --git a/modules/bullet/bullet_utilities.h b/modules/bullet/bullet_utilities.h
new file mode 100644
index 0000000000..45cde169b7
--- /dev/null
+++ b/modules/bullet/bullet_utilities.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* bullet_utilities.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BULLET_UTILITIES_H
+#define BULLET_UTILITIES_H
+
+#pragma once
+
+#define bulletnew(cl) \
+ new cl
+
+#define bulletdelete(cl) \
+ delete cl; \
+ cl = NULL;
+
+#endif
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
new file mode 100644
index 0000000000..769e2c943e
--- /dev/null
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -0,0 +1,320 @@
+/*************************************************************************/
+/* collision_object_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "collision_object_bullet.h"
+#include "area_bullet.h"
+#include "btBulletCollisionCommon.h"
+#include "bullet_physics_server.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "shape_bullet.h"
+#include "space_bullet.h"
+
+#define enableDynamicAabbTree true
+#define initialChildCapacity 1
+
+CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {}
+
+void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_transform) {
+ G_TO_B(p_transform, transform);
+}
+void CollisionObjectBullet::ShapeWrapper::set_transform(const btTransform &p_transform) {
+ transform = p_transform;
+}
+
+CollisionObjectBullet::CollisionObjectBullet(Type p_type)
+ : RIDBullet(), space(NULL), type(p_type), collisionsEnabled(true), m_isStatic(false), bt_collision_object(NULL), body_scale(1., 1., 1.) {}
+
+CollisionObjectBullet::~CollisionObjectBullet() {
+ // Remove all overlapping
+ for (int i = areasOverlapped.size() - 1; 0 <= i; --i) {
+ areasOverlapped[i]->remove_overlapping_instantly(this);
+ }
+ // not required
+ // areasOverlapped.clear();
+
+ destroyBulletCollisionObject();
+}
+
+bool equal(real_t first, real_t second) {
+ return Math::abs(first - second) <= 0.001f;
+}
+
+void CollisionObjectBullet::set_body_scale(const Vector3 &p_new_scale) {
+ if (!equal(p_new_scale[0], body_scale[0]) || !equal(p_new_scale[1], body_scale[1]) || !equal(p_new_scale[2], body_scale[2])) {
+ G_TO_B(p_new_scale, body_scale);
+ on_body_scale_changed();
+ }
+}
+
+void CollisionObjectBullet::on_body_scale_changed() {
+}
+
+void CollisionObjectBullet::destroyBulletCollisionObject() {
+ bulletdelete(bt_collision_object);
+}
+
+void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_collisionObject) {
+ bt_collision_object = p_collisionObject;
+ bt_collision_object->setUserPointer(this);
+ bt_collision_object->setUserIndex(type);
+ // Force the enabling of collision and avoid problems
+ set_collision_enabled(collisionsEnabled);
+}
+
+void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) {
+ exceptions.insert(p_ignoreCollisionObject->get_self());
+ bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, true);
+ if (space)
+ space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher());
+}
+
+void CollisionObjectBullet::remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) {
+ exceptions.erase(p_ignoreCollisionObject->get_self());
+ bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, false);
+ if (space)
+ space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher());
+}
+
+bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const {
+ return !bt_collision_object->checkCollideWithOverride(p_otherCollisionObject->bt_collision_object);
+}
+
+void CollisionObjectBullet::set_collision_enabled(bool p_enabled) {
+ collisionsEnabled = p_enabled;
+ if (collisionsEnabled) {
+ bt_collision_object->setCollisionFlags(bt_collision_object->getCollisionFlags() & (~btCollisionObject::CF_NO_CONTACT_RESPONSE));
+ } else {
+ bt_collision_object->setCollisionFlags(bt_collision_object->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
+ }
+}
+
+bool CollisionObjectBullet::is_collisions_response_enabled() {
+ return collisionsEnabled;
+}
+
+void CollisionObjectBullet::notify_new_overlap(AreaBullet *p_area) {
+ areasOverlapped.push_back(p_area);
+}
+
+void CollisionObjectBullet::on_exit_area(AreaBullet *p_area) {
+ areasOverlapped.erase(p_area);
+}
+
+void CollisionObjectBullet::set_godot_object_flags(int flags) {
+ bt_collision_object->setUserIndex2(flags);
+}
+
+int CollisionObjectBullet::get_godot_object_flags() const {
+ return bt_collision_object->getUserIndex2();
+}
+
+void CollisionObjectBullet::set_transform(const Transform &p_global_transform) {
+
+ btTransform btTrans;
+ Basis decomposed_basis;
+
+ Vector3 decomposed_scale = p_global_transform.get_basis().rotref_posscale_decomposition(decomposed_basis);
+
+ G_TO_B(p_global_transform.get_origin(), btTrans.getOrigin());
+ G_TO_B(decomposed_basis, btTrans.getBasis());
+
+ set_body_scale(decomposed_scale);
+ set_transform__bullet(btTrans);
+}
+
+Transform CollisionObjectBullet::get_transform() const {
+ Transform t;
+ B_TO_G(get_transform__bullet(), t);
+ return t;
+}
+
+void CollisionObjectBullet::set_transform__bullet(const btTransform &p_global_transform) {
+ bt_collision_object->setWorldTransform(p_global_transform);
+}
+
+const btTransform &CollisionObjectBullet::get_transform__bullet() const {
+ return bt_collision_object->getWorldTransform();
+}
+
+RigidCollisionObjectBullet::RigidCollisionObjectBullet(Type p_type)
+ : CollisionObjectBullet(p_type), compoundShape(bulletnew(btCompoundShape(enableDynamicAabbTree, initialChildCapacity))) {
+}
+
+RigidCollisionObjectBullet::~RigidCollisionObjectBullet() {
+ remove_all_shapes(true);
+ bt_collision_object->setCollisionShape(NULL);
+ bulletdelete(compoundShape);
+}
+
+/* Not used
+void RigidCollisionObjectBullet::_internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) {
+ bool at_least_one_was_changed = false;
+ btTransform old_transf;
+ // Inverse because I need remove the shapes
+ // Fetch all shapes to be sure to remove all shapes
+ for (int i = compoundShape->getNumChildShapes() - 1; 0 <= i; --i) {
+ if (compoundShape->getChildShape(i) == p_old_shape) {
+
+ old_transf = compoundShape->getChildTransform(i);
+ compoundShape->removeChildShapeByIndex(i);
+ compoundShape->addChildShape(old_transf, p_new_shape);
+ at_least_one_was_changed = true;
+ }
+ }
+
+ if (at_least_one_was_changed) {
+ on_shapes_changed();
+ }
+}*/
+
+void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform) {
+ shapes.push_back(ShapeWrapper(p_shape, p_transform, true));
+ p_shape->add_owner(this);
+ on_shapes_changed();
+}
+
+void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) {
+ ShapeWrapper &shp = shapes[p_index];
+ shp.shape->remove_owner(this);
+ p_shape->add_owner(this);
+ shp.shape = p_shape;
+ on_shapes_changed();
+}
+
+void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) {
+ ERR_FAIL_INDEX(p_index, get_shape_count());
+
+ shapes[p_index].set_transform(p_transform);
+ on_shapes_changed();
+}
+
+void RigidCollisionObjectBullet::remove_shape(ShapeBullet *p_shape) {
+ // Remove the shape, all the times it appears
+ // Reverse order required for delete.
+ for (int i = shapes.size() - 1; 0 <= i; --i) {
+ if (p_shape == shapes[i].shape) {
+ internal_shape_destroy(i);
+ shapes.remove(i);
+ }
+ }
+ on_shapes_changed();
+}
+
+void RigidCollisionObjectBullet::remove_shape(int p_index) {
+ ERR_FAIL_INDEX(p_index, get_shape_count());
+ internal_shape_destroy(p_index);
+ shapes.remove(p_index);
+ on_shapes_changed();
+}
+
+void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBody) {
+ // Reverse order required for delete.
+ for (int i = shapes.size() - 1; 0 <= i; --i) {
+ internal_shape_destroy(i, p_permanentlyFromThisBody);
+ }
+ shapes.clear();
+ on_shapes_changed();
+}
+
+int RigidCollisionObjectBullet::get_shape_count() const {
+ return shapes.size();
+}
+
+ShapeBullet *RigidCollisionObjectBullet::get_shape(int p_index) const {
+ return shapes[p_index].shape;
+}
+
+btCollisionShape *RigidCollisionObjectBullet::get_bt_shape(int p_index) const {
+ return shapes[p_index].bt_shape;
+}
+
+Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const {
+ Transform trs;
+ B_TO_G(shapes[p_index].transform, trs);
+ return trs;
+}
+
+void RigidCollisionObjectBullet::on_shape_changed(const ShapeBullet *const p_shape) {
+ const int size = shapes.size();
+ for (int i = 0; i < size; ++i) {
+ if (shapes[i].shape == p_shape) {
+ bulletdelete(shapes[i].bt_shape);
+ }
+ }
+ on_shapes_changed();
+}
+
+void RigidCollisionObjectBullet::on_shapes_changed() {
+ int i;
+ // Remove all shapes, reverse order for performance reason (Array resize)
+ for (i = compoundShape->getNumChildShapes() - 1; 0 <= i; --i) {
+ compoundShape->removeChildShapeByIndex(i);
+ }
+
+ // Insert all shapes
+ ShapeWrapper *shpWrapper;
+ const int size = shapes.size();
+ for (i = 0; i < size; ++i) {
+ shpWrapper = &shapes[i];
+ if (!shpWrapper->bt_shape) {
+ shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape();
+ }
+ if (shpWrapper->active) {
+ compoundShape->addChildShape(shpWrapper->transform, shpWrapper->bt_shape);
+ } else {
+ compoundShape->addChildShape(shpWrapper->transform, BulletPhysicsServer::get_empty_shape());
+ }
+ }
+
+ compoundShape->setLocalScaling(body_scale);
+ compoundShape->recalculateLocalAabb();
+}
+
+void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) {
+ shapes[p_index].active = !p_disabled;
+ on_shapes_changed();
+}
+
+bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) {
+ return !shapes[p_index].active;
+}
+
+void RigidCollisionObjectBullet::on_body_scale_changed() {
+ CollisionObjectBullet::on_body_scale_changed();
+ on_shapes_changed();
+}
+
+void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) {
+ ShapeWrapper &shp = shapes[p_index];
+ shp.shape->remove_owner(this, p_permanentlyFromThisBody);
+ bulletdelete(shp.bt_shape);
+}
diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h
new file mode 100644
index 0000000000..153b8ea5bc
--- /dev/null
+++ b/modules/bullet/collision_object_bullet.h
@@ -0,0 +1,234 @@
+/*************************************************************************/
+/* collision_object_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef COLLISION_OBJECT_BULLET_H
+#define COLLISION_OBJECT_BULLET_H
+
+#include "LinearMath/btTransform.h"
+#include "core/vset.h"
+#include "object.h"
+#include "shape_owner_bullet.h"
+#include "transform.h"
+#include "vector3.h"
+
+class AreaBullet;
+class ShapeBullet;
+class btCollisionObject;
+class btCompoundShape;
+class btCollisionShape;
+class SpaceBullet;
+
+class CollisionObjectBullet : public RIDBullet {
+public:
+ enum GodotObjectFlags {
+ GOF_IS_MONITORING_AREA = 1 << 0
+ // FLAG2 = 1 << 1,
+ // FLAG3 = 1 << 2,
+ // FLAG4 = 1 << 3,
+ // FLAG5 = 1 << 4,
+ // FLAG6 = 1 << 5
+ // etc..
+ };
+ enum Type {
+ TYPE_AREA = 0,
+ TYPE_RIGID_BODY,
+ TYPE_SOFT_BODY,
+ TYPE_KINEMATIC_GHOST_BODY
+ };
+
+ struct ShapeWrapper {
+ ShapeBullet *shape;
+ btCollisionShape *bt_shape;
+ btTransform transform;
+ bool active;
+
+ ShapeWrapper()
+ : shape(NULL), bt_shape(NULL), active(true) {}
+
+ ShapeWrapper(ShapeBullet *p_shape, const btTransform &p_transform, bool p_active)
+ : shape(p_shape), bt_shape(NULL), active(p_active) {
+ set_transform(p_transform);
+ }
+
+ ShapeWrapper(ShapeBullet *p_shape, const Transform &p_transform, bool p_active)
+ : shape(p_shape), bt_shape(NULL), active(p_active) {
+ set_transform(p_transform);
+ }
+ ~ShapeWrapper();
+
+ ShapeWrapper(const ShapeWrapper &otherShape) {
+ operator=(otherShape);
+ }
+
+ void operator=(const ShapeWrapper &otherShape) {
+ shape = otherShape.shape;
+ bt_shape = otherShape.bt_shape;
+ transform = otherShape.transform;
+ active = otherShape.active;
+ }
+
+ void set_transform(const Transform &p_transform);
+ void set_transform(const btTransform &p_transform);
+ };
+
+protected:
+ Type type;
+ ObjectID instance_id;
+ uint32_t collisionLayer;
+ uint32_t collisionMask;
+ bool collisionsEnabled;
+ bool m_isStatic;
+ bool ray_pickable;
+ btCollisionObject *bt_collision_object;
+ btVector3 body_scale;
+ SpaceBullet *space;
+
+ VSet<RID> exceptions;
+
+ /// This array is used to know all areas where this Object is overlapped in
+ /// New area is added when overlap with new area (AreaBullet::addOverlap), then is removed when it exit (CollisionObjectBullet::onExitArea)
+ /// This array is used mainly to know which area hold the pointer of this object
+ Vector<AreaBullet *> areasOverlapped;
+
+public:
+ CollisionObjectBullet(Type p_type);
+ virtual ~CollisionObjectBullet();
+
+ Type getType() { return type; }
+
+protected:
+ void destroyBulletCollisionObject();
+ void setupBulletCollisionObject(btCollisionObject *p_collisionObject);
+
+public:
+ _FORCE_INLINE_ btCollisionObject *get_bt_collision_object() { return bt_collision_object; }
+
+ _FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; }
+ _FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; }
+
+ _FORCE_INLINE_ bool is_static() const { return m_isStatic; }
+
+ _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; }
+ _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; }
+
+ void set_body_scale(const Vector3 &p_new_scale);
+ virtual void on_body_scale_changed();
+
+ void add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject);
+ void remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject);
+ bool has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const;
+ _FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; }
+
+ _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) {
+ collisionLayer = p_layer;
+ on_collision_filters_change();
+ }
+ _FORCE_INLINE_ uint32_t get_collision_layer() const { return collisionLayer; }
+
+ _FORCE_INLINE_ void set_collision_mask(uint32_t p_mask) {
+ collisionMask = p_mask;
+ on_collision_filters_change();
+ }
+ _FORCE_INLINE_ uint32_t get_collision_mask() const { return collisionMask; }
+
+ virtual void on_collision_filters_change() = 0;
+
+ _FORCE_INLINE_ bool test_collision_mask(CollisionObjectBullet *p_other) const {
+ return collisionLayer & p_other->collisionMask || p_other->collisionLayer & collisionMask;
+ }
+
+ virtual void reload_body() = 0;
+ virtual void set_space(SpaceBullet *p_space) = 0;
+ _FORCE_INLINE_ SpaceBullet *get_space() const { return space; }
+ /// This is an event that is called when a collision checker starts
+ virtual void on_collision_checker_start() = 0;
+
+ virtual void dispatch_callbacks() = 0;
+
+ void set_collision_enabled(bool p_enabled);
+ bool is_collisions_response_enabled();
+
+ void notify_new_overlap(AreaBullet *p_area);
+ virtual void on_enter_area(AreaBullet *p_area) = 0;
+ virtual void on_exit_area(AreaBullet *p_area);
+
+ /// GodotObjectFlags
+ void set_godot_object_flags(int flags);
+ int get_godot_object_flags() const;
+
+ void set_transform(const Transform &p_global_transform);
+ Transform get_transform() const;
+ virtual void set_transform__bullet(const btTransform &p_global_transform);
+ virtual const btTransform &get_transform__bullet() const;
+};
+
+class RigidCollisionObjectBullet : public CollisionObjectBullet, public ShapeOwnerBullet {
+protected:
+ /// This is required to combine some shapes together.
+ /// Since Godot allow to have multiple shapes for each body with custom relative location,
+ /// each body will attach the shapes using this class even if there is only one shape.
+ btCompoundShape *compoundShape;
+ Vector<ShapeWrapper> shapes;
+
+public:
+ RigidCollisionObjectBullet(Type p_type);
+ ~RigidCollisionObjectBullet();
+
+ _FORCE_INLINE_ const Vector<ShapeWrapper> &get_shapes_wrappers() const { return shapes; }
+
+ /// This is used to set new shape or replace existing
+ //virtual void _internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) = 0;
+ void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform());
+ void set_shape(int p_index, ShapeBullet *p_shape);
+ void set_shape_transform(int p_index, const Transform &p_transform);
+ virtual void remove_shape(ShapeBullet *p_shape);
+ void remove_shape(int p_index);
+ void remove_all_shapes(bool p_permanentlyFromThisBody = false);
+
+ virtual void on_shape_changed(const ShapeBullet *const p_shape);
+ virtual void on_shapes_changed();
+
+ _FORCE_INLINE_ btCompoundShape *get_compound_shape() const { return compoundShape; }
+ int get_shape_count() const;
+ ShapeBullet *get_shape(int p_index) const;
+ btCollisionShape *get_bt_shape(int p_index) const;
+ Transform get_shape_transform(int p_index) const;
+
+ void set_shape_disabled(int p_index, bool p_disabled);
+ bool is_shape_disabled(int p_index);
+
+ virtual void on_body_scale_changed();
+
+private:
+ void internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody = false);
+};
+
+#endif
diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp
new file mode 100644
index 0000000000..f6ac40e001
--- /dev/null
+++ b/modules/bullet/cone_twist_joint_bullet.cpp
@@ -0,0 +1,111 @@
+/*************************************************************************/
+/* cone_twist_joint_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "cone_twist_joint_bullet.h"
+#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "rigid_body_bullet.h"
+
+ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame)
+ : JointBullet() {
+ btTransform btFrameA;
+ G_TO_B(rbAFrame, btFrameA);
+ if (rbB) {
+ btTransform btFrameB;
+ G_TO_B(rbBFrame, btFrameB);
+ coneConstraint = bulletnew(btConeTwistConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB));
+ } else {
+ coneConstraint = bulletnew(btConeTwistConstraint(*rbA->get_bt_rigid_body(), btFrameA));
+ }
+ setup(coneConstraint);
+}
+
+void ConeTwistJointBullet::set_angular_only(bool angularOnly) {
+ coneConstraint->setAngularOnly(angularOnly);
+}
+
+void ConeTwistJointBullet::set_limit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness, real_t _biasFactor, real_t _relaxationFactor) {
+ coneConstraint->setLimit(_swingSpan1, _swingSpan2, _twistSpan, _softness, _biasFactor, _relaxationFactor);
+}
+
+int ConeTwistJointBullet::get_solve_twist_limit() {
+ return coneConstraint->getSolveTwistLimit();
+}
+
+int ConeTwistJointBullet::get_solve_swing_limit() {
+ return coneConstraint->getSolveSwingLimit();
+}
+
+real_t ConeTwistJointBullet::get_twist_limit_sign() {
+ return coneConstraint->getTwistLimitSign();
+}
+
+void ConeTwistJointBullet::set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value) {
+ switch (p_param) {
+ case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN:
+ coneConstraint->setLimit(5, p_value);
+ coneConstraint->setLimit(4, p_value);
+ break;
+ case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN:
+ coneConstraint->setLimit(3, p_value);
+ break;
+ case PhysicsServer::CONE_TWIST_JOINT_BIAS:
+ coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), p_value, coneConstraint->getRelaxationFactor());
+ break;
+ case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS:
+ coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), p_value, coneConstraint->getBiasFactor(), coneConstraint->getRelaxationFactor());
+ break;
+ case PhysicsServer::CONE_TWIST_JOINT_RELAXATION:
+ coneConstraint->setLimit(coneConstraint->getSwingSpan1(), coneConstraint->getSwingSpan2(), coneConstraint->getTwistSpan(), coneConstraint->getLimitSoftness(), coneConstraint->getBiasFactor(), p_value);
+ break;
+ default:
+ WARN_PRINT("This parameter is not supported by Bullet engine");
+ }
+}
+
+real_t ConeTwistJointBullet::get_param(PhysicsServer::ConeTwistJointParam p_param) const {
+ switch (p_param) {
+ case PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN:
+ return coneConstraint->getSwingSpan1();
+ case PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN:
+ return coneConstraint->getTwistSpan();
+ case PhysicsServer::CONE_TWIST_JOINT_BIAS:
+ return coneConstraint->getBiasFactor();
+ case PhysicsServer::CONE_TWIST_JOINT_SOFTNESS:
+ return coneConstraint->getLimitSoftness();
+ case PhysicsServer::CONE_TWIST_JOINT_RELAXATION:
+ return coneConstraint->getRelaxationFactor();
+ default:
+ WARN_PRINT("This parameter is not supported by Bullet engine");
+ return 0;
+ }
+}
diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h
new file mode 100644
index 0000000000..1ce5ef9826
--- /dev/null
+++ b/modules/bullet/cone_twist_joint_bullet.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* cone_twist_joint_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CONE_TWIST_JOINT_BULLET_H
+#define CONE_TWIST_JOINT_BULLET_H
+
+#include "joint_bullet.h"
+
+class RigidBodyBullet;
+
+class ConeTwistJointBullet : public JointBullet {
+ class btConeTwistConstraint *coneConstraint;
+
+public:
+ ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_CONE_TWIST; }
+
+ void set_angular_only(bool angularOnly);
+
+ void set_limit(real_t _swingSpan1, real_t _swingSpan2, real_t _twistSpan, real_t _softness = 0.8f, real_t _biasFactor = 0.3f, real_t _relaxationFactor = 1.0f);
+ int get_solve_twist_limit();
+
+ int get_solve_swing_limit();
+ real_t get_twist_limit_sign();
+
+ void set_param(PhysicsServer::ConeTwistJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer::ConeTwistJointParam p_param) const;
+};
+#endif
diff --git a/modules/bullet/config.py b/modules/bullet/config.py
new file mode 100644
index 0000000000..b00ea18328
--- /dev/null
+++ b/modules/bullet/config.py
@@ -0,0 +1,6 @@
+def can_build(platform):
+ return True
+
+def configure(env):
+ pass
+
diff --git a/modules/bullet/constraint_bullet.cpp b/modules/bullet/constraint_bullet.cpp
new file mode 100644
index 0000000000..08fc36f274
--- /dev/null
+++ b/modules/bullet/constraint_bullet.cpp
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* constraint_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "constraint_bullet.h"
+#include "collision_object_bullet.h"
+#include "space_bullet.h"
+
+ConstraintBullet::ConstraintBullet()
+ : space(NULL), constraint(NULL) {}
+
+void ConstraintBullet::setup(btTypedConstraint *p_constraint) {
+ constraint = p_constraint;
+ constraint->setUserConstraintPtr(this);
+}
+
+void ConstraintBullet::set_space(SpaceBullet *p_space) {
+ space = p_space;
+}
+
+void ConstraintBullet::destroy_internal_constraint() {
+ space->remove_constraint(this);
+}
diff --git a/modules/bullet/constraint_bullet.h b/modules/bullet/constraint_bullet.h
new file mode 100644
index 0000000000..b528ec6d7b
--- /dev/null
+++ b/modules/bullet/constraint_bullet.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* constraint_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CONSTRAINT_BULLET_H
+#define CONSTRAINT_BULLET_H
+
+#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
+#include "bullet_utilities.h"
+#include "rid_bullet.h"
+
+class RigidBodyBullet;
+class SpaceBullet;
+class btTypedConstraint;
+
+class ConstraintBullet : public RIDBullet {
+
+protected:
+ SpaceBullet *space;
+ btTypedConstraint *constraint;
+
+public:
+ ConstraintBullet();
+
+ virtual void setup(btTypedConstraint *p_constraint);
+ virtual void set_space(SpaceBullet *p_space);
+ virtual void destroy_internal_constraint();
+
+public:
+ virtual ~ConstraintBullet() {
+ bulletdelete(constraint);
+ constraint = NULL;
+ }
+
+ _FORCE_INLINE_ btTypedConstraint *get_bt_constraint() { return constraint; }
+};
+#endif
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
new file mode 100644
index 0000000000..647396c24c
--- /dev/null
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -0,0 +1,241 @@
+/*************************************************************************/
+/* generic_6dof_joint_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "generic_6dof_joint_bullet.h"
+#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "rigid_body_bullet.h"
+
+Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA)
+ : JointBullet() {
+
+ btTransform btFrameA;
+ G_TO_B(frameInA, btFrameA);
+
+ if (rbB) {
+ btTransform btFrameB;
+ G_TO_B(frameInB, btFrameB);
+
+ sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB, useLinearReferenceFrameA));
+ } else {
+ sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), btFrameA, useLinearReferenceFrameA));
+ }
+
+ setup(sixDOFConstraint);
+}
+
+Transform Generic6DOFJointBullet::getFrameOffsetA() const {
+ btTransform btTrs = sixDOFConstraint->getFrameOffsetA();
+ Transform gTrs;
+ B_TO_G(btTrs, gTrs);
+ return gTrs;
+}
+
+Transform Generic6DOFJointBullet::getFrameOffsetB() const {
+ btTransform btTrs = sixDOFConstraint->getFrameOffsetB();
+ Transform gTrs;
+ B_TO_G(btTrs, gTrs);
+ return gTrs;
+}
+
+Transform Generic6DOFJointBullet::getFrameOffsetA() {
+ btTransform btTrs = sixDOFConstraint->getFrameOffsetA();
+ Transform gTrs;
+ B_TO_G(btTrs, gTrs);
+ return gTrs;
+}
+
+Transform Generic6DOFJointBullet::getFrameOffsetB() {
+ btTransform btTrs = sixDOFConstraint->getFrameOffsetB();
+ Transform gTrs;
+ B_TO_G(btTrs, gTrs);
+ return gTrs;
+}
+
+void Generic6DOFJointBullet::set_linear_lower_limit(const Vector3 &linearLower) {
+ btVector3 btVec;
+ G_TO_B(linearLower, btVec);
+ sixDOFConstraint->setLinearLowerLimit(btVec);
+}
+
+void Generic6DOFJointBullet::set_linear_upper_limit(const Vector3 &linearUpper) {
+ btVector3 btVec;
+ G_TO_B(linearUpper, btVec);
+ sixDOFConstraint->setLinearUpperLimit(btVec);
+}
+
+void Generic6DOFJointBullet::set_angular_lower_limit(const Vector3 &angularLower) {
+ btVector3 btVec;
+ G_TO_B(angularLower, btVec);
+ sixDOFConstraint->setAngularLowerLimit(btVec);
+}
+
+void Generic6DOFJointBullet::set_angular_upper_limit(const Vector3 &angularUpper) {
+ btVector3 btVec;
+ G_TO_B(angularUpper, btVec);
+ sixDOFConstraint->setAngularUpperLimit(btVec);
+}
+
+void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value) {
+ ERR_FAIL_INDEX(p_axis, 3);
+ switch (p_param) {
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_lowerLimit[p_axis] = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_upperLimit[p_axis] = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_limitSoftness = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_restitution = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING:
+ sixDOFConstraint->getTranslationalLimitMotor()->m_damping = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_loLimit = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_hiLimit = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_limitSoftness = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_damping = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity = p_value;
+ break;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce = p_value;
+ break;
+ default:
+ WARN_PRINT("This parameter is not supported");
+ }
+}
+
+real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const {
+ ERR_FAIL_INDEX_V(p_axis, 3, 0.);
+ switch (p_param) {
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_lowerLimit[p_axis];
+ case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_upperLimit[p_axis];
+ case PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_limitSoftness;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_restitution;
+ case PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING:
+ return sixDOFConstraint->getTranslationalLimitMotor()->m_damping;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_loLimit;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_hiLimit;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_limitSoftness;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_damping;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_bounce;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_FORCE_LIMIT:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_targetVelocity;
+ case PhysicsServer::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxLimitForce;
+ default:
+ WARN_PRINT("This parameter is not supported");
+ return 0.;
+ }
+}
+
+void Generic6DOFJointBullet::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value) {
+ ERR_FAIL_INDEX(p_axis, 3);
+ switch (p_flag) {
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT:
+ if (p_value) {
+ if (!get_flag(p_axis, p_flag)) // avoid overwrite, if limited
+ sixDOFConstraint->setLimit(p_axis, 0, 0); // Limited
+ } else {
+ if (get_flag(p_axis, p_flag)) // avoid overwrite, if free
+ sixDOFConstraint->setLimit(p_axis, 0, -1); // Free
+ }
+ break;
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT: {
+ int angularAxis = 3 + p_axis;
+ if (p_value) {
+ if (!get_flag(p_axis, p_flag)) // avoid overwrite, if Limited
+ sixDOFConstraint->setLimit(angularAxis, 0, 0); // Limited
+ } else {
+ if (get_flag(p_axis, p_flag)) // avoid overwrite, if free
+ sixDOFConstraint->setLimit(angularAxis, 0, -1); // Free
+ }
+ break;
+ }
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR:
+ //sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] = p_value;
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableMotor = p_value;
+ break;
+ default:
+ WARN_PRINT("This flag is not supported by Bullet engine");
+ }
+}
+
+bool Generic6DOFJointBullet::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const {
+ ERR_FAIL_INDEX_V(p_axis, 3, false);
+ switch (p_flag) {
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT:
+ return sixDOFConstraint->getTranslationalLimitMotor()->isLimited(p_axis);
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT:
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->isLimited();
+ case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR:
+ return //sixDOFConstraint->getTranslationalLimitMotor()->m_enableMotor[p_axis] &&
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_enableMotor;
+ default:
+ WARN_PRINT("This flag is not supported by Bullet engine");
+ return false;
+ }
+}
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
new file mode 100644
index 0000000000..0d47b823de
--- /dev/null
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -0,0 +1,65 @@
+/*************************************************************************/
+/* generic_6dof_joint_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GENERIC_6DOF_JOINT_BULLET_H
+#define GENERIC_6DOF_JOINT_BULLET_H
+
+#include "joint_bullet.h"
+
+class RigidBodyBullet;
+
+class Generic6DOFJointBullet : public JointBullet {
+ class btGeneric6DofConstraint *sixDOFConstraint;
+
+public:
+ Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA);
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; }
+
+ Transform getFrameOffsetA() const;
+ Transform getFrameOffsetB() const;
+ Transform getFrameOffsetA();
+ Transform getFrameOffsetB();
+
+ void set_linear_lower_limit(const Vector3 &linearLower);
+ void set_linear_upper_limit(const Vector3 &linearUpper);
+
+ void set_angular_lower_limit(const Vector3 &angularLower);
+ void set_angular_upper_limit(const Vector3 &angularUpper);
+
+ void set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param, real_t p_value);
+ real_t get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisParam p_param) const;
+
+ void set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag, bool p_value);
+ bool get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJointAxisFlag p_flag) const;
+};
+
+#endif
diff --git a/modules/bullet/godot_collision_configuration.cpp b/modules/bullet/godot_collision_configuration.cpp
new file mode 100644
index 0000000000..4e4228cc48
--- /dev/null
+++ b/modules/bullet/godot_collision_configuration.cpp
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* godot_collision_configuration.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "godot_collision_configuration.h"
+#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
+#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
+#include "godot_ray_world_algorithm.h"
+
+GodotCollisionConfiguration::GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo)
+ : btDefaultCollisionConfiguration(constructionInfo) {
+
+ void *mem = NULL;
+
+ mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::CreateFunc), 16);
+ m_rayWorldCF = new (mem) GodotRayWorldAlgorithm::CreateFunc(world);
+
+ mem = btAlignedAlloc(sizeof(GodotRayWorldAlgorithm::SwappedCreateFunc), 16);
+ m_swappedRayWorldCF = new (mem) GodotRayWorldAlgorithm::SwappedCreateFunc(world);
+}
+
+GodotCollisionConfiguration::~GodotCollisionConfiguration() {
+ m_rayWorldCF->~btCollisionAlgorithmCreateFunc();
+ btAlignedFree(m_rayWorldCF);
+
+ m_swappedRayWorldCF->~btCollisionAlgorithmCreateFunc();
+ btAlignedFree(m_swappedRayWorldCF);
+}
+
+btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1) {
+
+ if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) {
+
+ // This collision is not supported
+ return m_emptyCreateFunc;
+ } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) {
+
+ return m_rayWorldCF;
+ } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) {
+
+ return m_swappedRayWorldCF;
+ } else {
+
+ return btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(proxyType0, proxyType1);
+ }
+}
+
+btCollisionAlgorithmCreateFunc *GodotCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) {
+
+ if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0 && CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) {
+
+ // This collision is not supported
+ return m_emptyCreateFunc;
+ } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType0) {
+
+ return m_rayWorldCF;
+ } else if (CUSTOM_CONVEX_SHAPE_TYPE == proxyType1) {
+
+ return m_swappedRayWorldCF;
+ } else {
+
+ return btDefaultCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(proxyType0, proxyType1);
+ }
+}
diff --git a/modules/bullet/godot_collision_configuration.h b/modules/bullet/godot_collision_configuration.h
new file mode 100644
index 0000000000..ed99065f8c
--- /dev/null
+++ b/modules/bullet/godot_collision_configuration.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* godot_collision_configuration.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_COLLISION_CONFIGURATION_H
+#define GODOT_COLLISION_CONFIGURATION_H
+
+#include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h"
+
+class btDiscreteDynamicsWorld;
+
+class GodotCollisionConfiguration : public btDefaultCollisionConfiguration {
+ btCollisionAlgorithmCreateFunc *m_rayWorldCF;
+ btCollisionAlgorithmCreateFunc *m_swappedRayWorldCF;
+
+public:
+ GodotCollisionConfiguration(const btDiscreteDynamicsWorld *world, const btDefaultCollisionConstructionInfo &constructionInfo = btDefaultCollisionConstructionInfo());
+ virtual ~GodotCollisionConfiguration();
+
+ virtual btCollisionAlgorithmCreateFunc *getCollisionAlgorithmCreateFunc(int proxyType0, int proxyType1);
+ virtual btCollisionAlgorithmCreateFunc *getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1);
+};
+#endif
diff --git a/modules/bullet/godot_collision_dispatcher.cpp b/modules/bullet/godot_collision_dispatcher.cpp
new file mode 100644
index 0000000000..ea75e4eef4
--- /dev/null
+++ b/modules/bullet/godot_collision_dispatcher.cpp
@@ -0,0 +1,54 @@
+/*************************************************************************/
+/* godot_collision_dispatcher.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "godot_collision_dispatcher.h"
+#include "collision_object_bullet.h"
+
+const int GodotCollisionDispatcher::CASTED_TYPE_AREA = static_cast<int>(CollisionObjectBullet::TYPE_AREA);
+
+GodotCollisionDispatcher::GodotCollisionDispatcher(btCollisionConfiguration *collisionConfiguration)
+ : btCollisionDispatcher(collisionConfiguration) {}
+
+bool GodotCollisionDispatcher::needsCollision(const btCollisionObject *body0, const btCollisionObject *body1) {
+ if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) {
+ // Avoide area narrow phase
+ return false;
+ }
+ return btCollisionDispatcher::needsCollision(body0, body1);
+}
+
+bool GodotCollisionDispatcher::needsResponse(const btCollisionObject *body0, const btCollisionObject *body1) {
+ if (body0->getUserIndex() == CASTED_TYPE_AREA || body1->getUserIndex() == CASTED_TYPE_AREA) {
+ // Avoide area narrow phase
+ return false;
+ }
+ return btCollisionDispatcher::needsResponse(body0, body1);
+}
diff --git a/modules/bullet/godot_collision_dispatcher.h b/modules/bullet/godot_collision_dispatcher.h
new file mode 100644
index 0000000000..501b2078dd
--- /dev/null
+++ b/modules/bullet/godot_collision_dispatcher.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* godot_collision_dispatcher.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_COLLISION_DISPATCHER_H
+#define GODOT_COLLISION_DISPATCHER_H
+
+#include "int_types.h"
+#include <btBulletDynamicsCommon.h>
+
+/// This class is required to implement custom collision behaviour in the narrowphase
+class GodotCollisionDispatcher : public btCollisionDispatcher {
+private:
+ static const int CASTED_TYPE_AREA;
+
+public:
+ GodotCollisionDispatcher(btCollisionConfiguration *collisionConfiguration);
+ virtual bool needsCollision(const btCollisionObject *body0, const btCollisionObject *body1);
+ virtual bool needsResponse(const btCollisionObject *body0, const btCollisionObject *body1);
+};
+#endif
diff --git a/modules/bullet/godot_motion_state.h b/modules/bullet/godot_motion_state.h
new file mode 100644
index 0000000000..5111807394
--- /dev/null
+++ b/modules/bullet/godot_motion_state.h
@@ -0,0 +1,96 @@
+/*************************************************************************/
+/* godot_motion_state.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_MOTION_STATE_H
+#define GODOT_MOTION_STATE_H
+
+#include "LinearMath/btMotionState.h"
+#include "rigid_body_bullet.h"
+
+class RigidBodyBullet;
+
+// This clas is responsible to move kinematic actor
+// and sincronize rendering engine with Bullet
+/// DOC:
+/// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/MotionStates#What.27s_a_MotionState.3F
+class GodotMotionState : public btMotionState {
+
+ /// This data is used to store the new world position for kinematic body
+ btTransform bodyKinematicWorldTransf;
+ /// This data is used to store last world position
+ btTransform bodyCurrentWorldTransform;
+
+ RigidBodyBullet *owner;
+
+public:
+ GodotMotionState(RigidBodyBullet *p_owner)
+ : bodyKinematicWorldTransf(btMatrix3x3(1., 0., 0., 0., 1., 0., 0., 0., 1.), btVector3(0., 0., 0.)),
+ bodyCurrentWorldTransform(btMatrix3x3(1., 0., 0., 0., 1., 0., 0., 0., 1.), btVector3(0., 0., 0.)),
+ owner(p_owner) {}
+
+ /// IMPORTANT DON'T USE THIS FUNCTION TO KNOW THE CURRENT BODY TRANSFORM
+ /// This class is used internally by Bullet
+ /// Use GodotMotionState::getCurrentWorldTransform to know current position
+ ///
+ /// This function is used by Bullet to get the position of object in the world
+ /// if the body is kinematic Bullet will move the object to this location
+ /// if the body is static Bullet doesn't move at all
+ virtual void getWorldTransform(btTransform &worldTrans) const {
+ worldTrans = bodyKinematicWorldTransf;
+ }
+
+ /// IMPORTANT: to move the body use: moveBody
+ /// IMPORTANT: DON'T CALL THIS FUNCTION, IT IS CALLED BY BULLET TO UPDATE RENDERING ENGINE
+ ///
+ /// This function is called each time by Bullet and set the current position of body
+ /// inside the physics world.
+ /// Don't allow Godot rendering scene takes world transform from this object because
+ /// the correct transform is set by Bullet only after the last step when there are sub steps
+ /// This function must update Godot transform rendering scene for this object.
+ virtual void setWorldTransform(const btTransform &worldTrans) {
+ bodyCurrentWorldTransform = worldTrans;
+
+ owner->scratch();
+ }
+
+public:
+ /// Use this function to move kinematic body
+ /// -- or set initial transfom before body creation.
+ void moveBody(const btTransform &newWorldTransform) {
+ bodyKinematicWorldTransf = newWorldTransform;
+ }
+
+ /// It returns the current body transform from last Bullet update
+ const btTransform &getCurrentWorldTransform() const {
+ return bodyCurrentWorldTransform;
+ }
+};
+#endif
diff --git a/modules/bullet/godot_ray_world_algorithm.cpp b/modules/bullet/godot_ray_world_algorithm.cpp
new file mode 100644
index 0000000000..98daf8398e
--- /dev/null
+++ b/modules/bullet/godot_ray_world_algorithm.cpp
@@ -0,0 +1,104 @@
+/*************************************************************************/
+/* godot_ray_world_algorithm.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "godot_ray_world_algorithm.h"
+#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
+#include "btRayShape.h"
+#include "collision_object_bullet.h"
+
+GodotRayWorldAlgorithm::CreateFunc::CreateFunc(const btDiscreteDynamicsWorld *world)
+ : m_world(world) {}
+
+GodotRayWorldAlgorithm::SwappedCreateFunc::SwappedCreateFunc(const btDiscreteDynamicsWorld *world)
+ : m_world(world) {}
+
+GodotRayWorldAlgorithm::GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped)
+ : btActivatingCollisionAlgorithm(ci, body0Wrap, body1Wrap),
+ m_manifoldPtr(mf),
+ m_ownManifold(false),
+ m_world(world),
+ m_isSwapped(isSwapped) {}
+
+GodotRayWorldAlgorithm::~GodotRayWorldAlgorithm() {
+ if (m_ownManifold && m_manifoldPtr) {
+ m_dispatcher->releaseManifold(m_manifoldPtr);
+ }
+}
+
+void GodotRayWorldAlgorithm::processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut) {
+
+ if (!m_manifoldPtr) {
+ if (m_isSwapped) {
+ m_manifoldPtr = m_dispatcher->getNewManifold(body1Wrap->getCollisionObject(), body0Wrap->getCollisionObject());
+ } else {
+ m_manifoldPtr = m_dispatcher->getNewManifold(body0Wrap->getCollisionObject(), body1Wrap->getCollisionObject());
+ }
+ m_ownManifold = true;
+ }
+ m_manifoldPtr->clearManifold();
+ resultOut->setPersistentManifold(m_manifoldPtr);
+
+ const btRayShape *ray_shape;
+ btTransform ray_transform;
+
+ const btCollisionObjectWrapper *other_co_wrapper;
+
+ if (m_isSwapped) {
+
+ ray_shape = static_cast<const btRayShape *>(body1Wrap->getCollisionShape());
+ ray_transform = body1Wrap->getWorldTransform();
+
+ other_co_wrapper = body0Wrap;
+ } else {
+
+ ray_shape = static_cast<const btRayShape *>(body0Wrap->getCollisionShape());
+ ray_transform = body0Wrap->getWorldTransform();
+
+ other_co_wrapper = body1Wrap;
+ }
+
+ btTransform to(ray_transform * ray_shape->getSupportPoint());
+
+ btCollisionWorld::ClosestRayResultCallback btResult(ray_transform.getOrigin(), to.getOrigin());
+
+ m_world->rayTestSingleInternal(ray_transform, to, other_co_wrapper, btResult);
+
+ if (btResult.hasHit()) {
+ btVector3 ray_normal(to.getOrigin() - ray_transform.getOrigin());
+ ray_normal.normalize();
+ ray_normal *= -1;
+ resultOut->addContactPoint(ray_normal, btResult.m_hitPointWorld, ray_shape->getScaledLength() * (btResult.m_closestHitFraction - 1));
+ }
+}
+
+btScalar GodotRayWorldAlgorithm::calculateTimeOfImpact(btCollisionObject *body0, btCollisionObject *body1, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut) {
+ return 1;
+}
diff --git a/modules/bullet/godot_ray_world_algorithm.h b/modules/bullet/godot_ray_world_algorithm.h
new file mode 100644
index 0000000000..15c71b8d7d
--- /dev/null
+++ b/modules/bullet/godot_ray_world_algorithm.h
@@ -0,0 +1,83 @@
+/*************************************************************************/
+/* godot_ray_world_algorithm.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_RAY_WORLD_ALGORITHM_H
+#define GODOT_RAY_WORLD_ALGORITHM_H
+
+#include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h"
+#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h"
+#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
+
+class btDiscreteDynamicsWorld;
+
+class GodotRayWorldAlgorithm : public btActivatingCollisionAlgorithm {
+
+ const btDiscreteDynamicsWorld *m_world;
+ btPersistentManifold *m_manifoldPtr;
+ bool m_ownManifold;
+ bool m_isSwapped;
+
+public:
+ GodotRayWorldAlgorithm(const btDiscreteDynamicsWorld *m_world, btPersistentManifold *mf, const btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, bool isSwapped);
+ virtual ~GodotRayWorldAlgorithm();
+
+ virtual void processCollision(const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut);
+ virtual btScalar calculateTimeOfImpact(btCollisionObject *body0, btCollisionObject *body1, const btDispatcherInfo &dispatchInfo, btManifoldResult *resultOut);
+
+ virtual void getAllContactManifolds(btManifoldArray &manifoldArray) {
+ ///should we use m_ownManifold to avoid adding duplicates?
+ if (m_manifoldPtr && m_ownManifold)
+ manifoldArray.push_back(m_manifoldPtr);
+ }
+ struct CreateFunc : public btCollisionAlgorithmCreateFunc {
+
+ const btDiscreteDynamicsWorld *m_world;
+ CreateFunc(const btDiscreteDynamicsWorld *world);
+
+ virtual btCollisionAlgorithm *CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) {
+ void *mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(GodotRayWorldAlgorithm));
+ return new (mem) GodotRayWorldAlgorithm(m_world, ci.m_manifold, ci, body0Wrap, body1Wrap, false);
+ }
+ };
+
+ struct SwappedCreateFunc : public btCollisionAlgorithmCreateFunc {
+
+ const btDiscreteDynamicsWorld *m_world;
+ SwappedCreateFunc(const btDiscreteDynamicsWorld *world);
+
+ virtual btCollisionAlgorithm *CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo &ci, const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) {
+ void *mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(GodotRayWorldAlgorithm));
+ return new (mem) GodotRayWorldAlgorithm(m_world, ci.m_manifold, ci, body0Wrap, body1Wrap, true);
+ }
+ };
+};
+
+#endif // GODOT_RAY_WORLD_ALGORITHM_H
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
new file mode 100644
index 0000000000..409d12f080
--- /dev/null
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -0,0 +1,291 @@
+/*************************************************************************/
+/* godot_result_callbacks.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "godot_result_callbacks.h"
+#include "bullet_types_converter.h"
+#include "collision_object_bullet.h"
+#include "rigid_body_bullet.h"
+
+bool GodotFilterCallback::test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask) {
+ return body0_collision_layer & body1_collision_mask || body1_collision_layer & body0_collision_mask;
+}
+
+bool GodotFilterCallback::needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const {
+ return GodotFilterCallback::test_collision_filters(proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask, proxy1->m_collisionFilterGroup, proxy1->m_collisionFilterMask);
+}
+
+bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (m_pickRay && gObj->is_ray_pickable()) {
+ return true;
+ } else if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) {
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(convexResult.m_hitCollisionObject->getUserPointer());
+
+ PhysicsDirectSpaceState::ShapeResult &result = m_results[count];
+
+ result.shape = convexResult.m_localShapeInfo->m_shapePart;
+ result.rid = gObj->get_self();
+ result.collider_id = gObj->get_instance_id();
+ result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id);
+
+ ++count;
+ return count < m_resultMax;
+}
+
+bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (gObj == m_self_object) {
+ return false;
+ } else {
+ if (m_ignore_areas && gObj->getType() == CollisionObjectBullet::TYPE_AREA) {
+ return false;
+ } else if (m_self_object->has_collision_exception(gObj)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+btScalar GodotClosestConvexResultCallback::addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace) {
+ btScalar res = btCollisionWorld::ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
+ m_shapePart = convexResult.m_localShapeInfo->m_shapePart;
+ return res;
+}
+
+bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+btScalar GodotAllContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
+
+ if (cp.getDistance() <= 0) {
+
+ PhysicsDirectSpaceState::ShapeResult &result = m_results[m_count];
+ // Penetrated
+
+ CollisionObjectBullet *colObj;
+ if (m_self_object == colObj0Wrap->getCollisionObject()) {
+ colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer());
+ result.shape = cp.m_index1;
+ } else {
+ colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer());
+ result.shape = cp.m_index0;
+ }
+
+ if (colObj)
+ result.collider_id = colObj->get_instance_id();
+ else
+ result.collider_id = 0;
+ result.collider = 0 == result.collider_id ? NULL : ObjectDB::get_instance(result.collider_id);
+ result.rid = colObj->get_self();
+ ++m_count;
+ }
+
+ return m_count < m_resultMax;
+}
+
+bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
+
+ if (m_self_object == colObj0Wrap->getCollisionObject()) {
+ B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 0]); // Local contact
+ B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 1]);
+ } else {
+ B_TO_G(cp.m_localPointB, m_results[m_count * 2 + 0]); // Local contact
+ B_TO_G(cp.m_localPointA, m_results[m_count * 2 + 1]);
+ }
+
+ ++m_count;
+
+ return m_count < m_resultMax;
+}
+
+bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (m_exclude->has(gObj->get_self())) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+btScalar GodotRestInfoContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
+
+ if (cp.getDistance() <= m_min_distance) {
+ m_min_distance = cp.getDistance();
+
+ CollisionObjectBullet *colObj;
+ if (m_self_object == colObj0Wrap->getCollisionObject()) {
+ colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer());
+ m_result->shape = cp.m_index1;
+ B_TO_G(cp.getPositionWorldOnB(), m_result->point);
+ m_rest_info_bt_point = cp.getPositionWorldOnB();
+ m_rest_info_collision_object = colObj1Wrap->getCollisionObject();
+ } else {
+ colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer());
+ m_result->shape = cp.m_index0;
+ B_TO_G(cp.m_normalWorldOnB * -1, m_result->normal);
+ m_rest_info_bt_point = cp.getPositionWorldOnA();
+ m_rest_info_collision_object = colObj0Wrap->getCollisionObject();
+ }
+
+ if (colObj)
+ m_result->collider_id = colObj->get_instance_id();
+ else
+ m_result->collider_id = 0;
+ m_result->rid = colObj->get_self();
+
+ m_collided = true;
+ }
+
+ return cp.getDistance();
+}
+
+bool GodotRecoverAndClosestContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const {
+ const bool needs = GodotFilterCallback::test_collision_filters(m_collisionFilterGroup, m_collisionFilterMask, proxy0->m_collisionFilterGroup, proxy0->m_collisionFilterMask);
+ if (needs) {
+ btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ if (gObj == m_self_object) {
+ return false;
+ } else {
+ if (m_ignore_areas && gObj->getType() == CollisionObjectBullet::TYPE_AREA) {
+ return false;
+ } else if (m_self_object->has_collision_exception(gObj)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+btScalar GodotRecoverAndClosestContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) {
+
+ if (cp.getDistance() < -MAX_PENETRATION_DEPTH) {
+ if (m_most_penetrated_distance > cp.getDistance()) {
+ m_most_penetrated_distance = cp.getDistance();
+
+ // take other object
+ btScalar sign(1);
+ if (m_self_object == colObj0Wrap->getCollisionObject()->getUserPointer()) {
+ m_pointCollisionObject = colObj1Wrap->getCollisionObject();
+ m_other_compound_shape_index = cp.m_index1;
+ } else {
+ m_pointCollisionObject = colObj0Wrap->getCollisionObject();
+ sign = -1;
+ m_other_compound_shape_index = cp.m_index0;
+ }
+
+ m_pointNormalWorld = cp.m_normalWorldOnB * sign;
+ m_pointWorld = cp.getPositionWorldOnB();
+ m_penetration_distance = cp.getDistance();
+
+ m_recover_penetration -= cp.m_normalWorldOnB * sign * (cp.getDistance() + MAX_PENETRATION_DEPTH);
+ }
+ }
+ return 1;
+}
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
new file mode 100644
index 0000000000..d505bd0de1
--- /dev/null
+++ b/modules/bullet/godot_result_callbacks.h
@@ -0,0 +1,189 @@
+/*************************************************************************/
+/* godot_result_callbacks.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_RESULT_CALLBACKS_H
+#define GODOT_RESULT_CALLBACKS_H
+
+#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
+#include "btBulletDynamicsCommon.h"
+#include "servers/physics_server.h"
+
+#define MAX_PENETRATION_DEPTH 0.005
+
+class RigidBodyBullet;
+
+/// This class is required to implement custom collision behaviour in the broadphase
+struct GodotFilterCallback : public btOverlapFilterCallback {
+ static bool test_collision_filters(uint32_t body0_collision_layer, uint32_t body0_collision_mask, uint32_t body1_collision_layer, uint32_t body1_collision_mask);
+
+ // return true when pairs need collision
+ virtual bool needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const;
+};
+
+/// It performs an additional check allow exclusions.
+struct GodotClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback {
+ const Set<RID> *m_exclude;
+ bool m_pickRay;
+
+public:
+ GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude)
+ : btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld), m_exclude(p_exclude), m_pickRay(false) {}
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+};
+
+// store all colliding object
+struct GodotAllConvexResultCallback : public btCollisionWorld::ConvexResultCallback {
+public:
+ PhysicsDirectSpaceState::ShapeResult *m_results;
+ int m_resultMax;
+ int count;
+ const Set<RID> *m_exclude;
+
+ GodotAllConvexResultCallback(PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude)
+ : m_results(p_results), m_exclude(p_exclude), m_resultMax(p_resultMax), count(0) {}
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+
+ virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace);
+};
+
+struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
+public:
+ const RigidBodyBullet *m_self_object;
+ const bool m_ignore_areas;
+
+ GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_ignore_areas)
+ : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_self_object(p_self_object), m_ignore_areas(p_ignore_areas) {}
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+};
+
+struct GodotClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
+public:
+ const Set<RID> *m_exclude;
+ int m_shapePart;
+
+ GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude)
+ : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_exclude(p_exclude) {}
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+
+ virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult &convexResult, bool normalInWorldSpace);
+};
+
+struct GodotAllContactResultCallback : public btCollisionWorld::ContactResultCallback {
+public:
+ const btCollisionObject *m_self_object;
+ PhysicsDirectSpaceState::ShapeResult *m_results;
+ int m_resultMax;
+ int m_count;
+ const Set<RID> *m_exclude;
+
+ GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude)
+ : m_self_object(p_self_object), m_results(p_results), m_exclude(p_exclude), m_resultMax(p_resultMax), m_count(0) {}
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+
+ virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1);
+};
+
+/// Returns the list of contacts pairs in this order: Local contact, other body contact
+struct GodotContactPairContactResultCallback : public btCollisionWorld::ContactResultCallback {
+public:
+ const btCollisionObject *m_self_object;
+ Vector3 *m_results;
+ int m_resultMax;
+ int m_count;
+ const Set<RID> *m_exclude;
+
+ GodotContactPairContactResultCallback(btCollisionObject *p_self_object, Vector3 *p_results, int p_resultMax, const Set<RID> *p_exclude)
+ : m_self_object(p_self_object), m_results(p_results), m_exclude(p_exclude), m_resultMax(p_resultMax), m_count(0) {}
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+
+ virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1);
+};
+
+struct GodotRestInfoContactResultCallback : public btCollisionWorld::ContactResultCallback {
+public:
+ const btCollisionObject *m_self_object;
+ PhysicsDirectSpaceState::ShapeRestInfo *m_result;
+ bool m_collided;
+ real_t m_min_distance;
+ const btCollisionObject *m_rest_info_collision_object;
+ btVector3 m_rest_info_bt_point;
+ const Set<RID> *m_exclude;
+
+ GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeRestInfo *p_result, const Set<RID> *p_exclude)
+ : m_self_object(p_self_object), m_result(p_result), m_exclude(p_exclude), m_collided(false), m_min_distance(0) {}
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+
+ virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1);
+};
+
+struct GodotRecoverAndClosestContactResultCallback : public btCollisionWorld::ContactResultCallback {
+public:
+ btVector3 m_pointNormalWorld;
+ btVector3 m_pointWorld;
+ btScalar m_penetration_distance;
+ int m_other_compound_shape_index;
+ const btCollisionObject *m_pointCollisionObject;
+
+ const RigidBodyBullet *m_self_object;
+ bool m_ignore_areas;
+
+ btScalar m_most_penetrated_distance;
+ btVector3 m_recover_penetration;
+
+ GodotRecoverAndClosestContactResultCallback()
+ : m_pointCollisionObject(NULL), m_penetration_distance(0), m_other_compound_shape_index(0), m_self_object(NULL), m_ignore_areas(true), m_most_penetrated_distance(1e20), m_recover_penetration(0, 0, 0) {}
+
+ GodotRecoverAndClosestContactResultCallback(const RigidBodyBullet *p_self_object, bool p_ignore_areas)
+ : m_pointCollisionObject(NULL), m_penetration_distance(0), m_other_compound_shape_index(0), m_self_object(p_self_object), m_ignore_areas(p_ignore_areas), m_most_penetrated_distance(9999999999), m_recover_penetration(0, 0, 0) {}
+
+ void reset() {
+ m_pointCollisionObject = NULL;
+ m_most_penetrated_distance = 1e20;
+ m_recover_penetration.setZero();
+ }
+
+ bool hasHit() {
+ return m_pointCollisionObject;
+ }
+
+ virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
+
+ virtual btScalar addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1);
+};
+
+#endif // GODOT_RESULT_CALLBACKS_H
diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp
new file mode 100644
index 0000000000..bb70babd99
--- /dev/null
+++ b/modules/bullet/hinge_joint_bullet.cpp
@@ -0,0 +1,163 @@
+/*************************************************************************/
+/* hinge_joint_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "hinge_joint_bullet.h"
+#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "rigid_body_bullet.h"
+
+HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB)
+ : JointBullet() {
+ btTransform btFrameA;
+ G_TO_B(frameA, btFrameA);
+
+ if (rbB) {
+ btTransform btFrameB;
+ G_TO_B(frameB, btFrameB);
+
+ hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB));
+ } else {
+
+ hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), btFrameA));
+ }
+
+ setup(hingeConstraint);
+}
+
+HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB)
+ : JointBullet() {
+
+ btVector3 btPivotA;
+ btVector3 btAxisA;
+ G_TO_B(pivotInA, btPivotA);
+ G_TO_B(axisInA, btAxisA);
+
+ if (rbB) {
+ btVector3 btPivotB;
+ btVector3 btAxisB;
+ G_TO_B(pivotInB, btPivotB);
+ G_TO_B(axisInB, btAxisB);
+
+ hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btPivotA, btPivotB, btAxisA, btAxisB));
+ } else {
+
+ hingeConstraint = bulletnew(btHingeConstraint(*rbA->get_bt_rigid_body(), btPivotA, btAxisA));
+ }
+
+ setup(hingeConstraint);
+}
+
+real_t HingeJointBullet::get_hinge_angle() {
+ return hingeConstraint->getHingeAngle();
+}
+
+void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t p_value) {
+ switch (p_param) {
+ case PhysicsServer::HINGE_JOINT_BIAS:
+ if (0 < p_value) {
+ print_line("The Bullet Hinge Joint doesn't support bias, So it's always 0");
+ }
+ break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_UPPER:
+ hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), p_value, hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor());
+ break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_LOWER:
+ hingeConstraint->setLimit(p_value, hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor());
+ break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_BIAS:
+ hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), p_value, hingeConstraint->getLimitRelaxationFactor());
+ break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS:
+ hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), p_value, hingeConstraint->getLimitBiasFactor(), hingeConstraint->getLimitRelaxationFactor());
+ break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION:
+ hingeConstraint->setLimit(hingeConstraint->getLowerLimit(), hingeConstraint->getUpperLimit(), hingeConstraint->getLimitSoftness(), hingeConstraint->getLimitBiasFactor(), p_value);
+ break;
+ case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
+ hingeConstraint->setMotorTargetVelocity(p_value);
+ break;
+ case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE:
+ hingeConstraint->setMaxMotorImpulse(p_value);
+ break;
+ default:
+ WARN_PRINTS("The Bullet Hinge Joint doesn't support this parameter: " + itos(p_param) + ", value: " + itos(p_value));
+ }
+}
+
+real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const {
+ switch (p_param) {
+ case PhysicsServer::HINGE_JOINT_BIAS:
+ return 0;
+ break;
+ case PhysicsServer::HINGE_JOINT_LIMIT_UPPER:
+ return hingeConstraint->getUpperLimit();
+ case PhysicsServer::HINGE_JOINT_LIMIT_LOWER:
+ return hingeConstraint->getLowerLimit();
+ case PhysicsServer::HINGE_JOINT_LIMIT_BIAS:
+ return hingeConstraint->getLimitBiasFactor();
+ case PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS:
+ return hingeConstraint->getLimitSoftness();
+ case PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION:
+ return hingeConstraint->getLimitRelaxationFactor();
+ case PhysicsServer::HINGE_JOINT_MOTOR_TARGET_VELOCITY:
+ return hingeConstraint->getMotorTargetVelocity();
+ case PhysicsServer::HINGE_JOINT_MOTOR_MAX_IMPULSE:
+ return hingeConstraint->getMaxMotorImpulse();
+ default:
+ WARN_PRINTS("The Bullet Hinge Joint doesn't support this parameter: " + itos(p_param));
+ return 0;
+ }
+}
+
+void HingeJointBullet::set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value) {
+ switch (p_flag) {
+ case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT:
+ if (!p_value) {
+ hingeConstraint->setLimit(-Math_PI, Math_PI);
+ }
+ break;
+ case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:
+ hingeConstraint->enableMotor(p_value);
+ break;
+ }
+}
+
+bool HingeJointBullet::get_flag(PhysicsServer::HingeJointFlag p_flag) const {
+ switch (p_flag) {
+ case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT:
+ return true;
+ case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:
+ return hingeConstraint->getEnableAngularMotor();
+ default:
+ return false;
+ }
+}
diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h
new file mode 100644
index 0000000000..a78788a5e5
--- /dev/null
+++ b/modules/bullet/hinge_joint_bullet.h
@@ -0,0 +1,54 @@
+/*************************************************************************/
+/* hinge_joint_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef HINGE_JOINT_BULLET_H
+#define HINGE_JOINT_BULLET_H
+
+#include "joint_bullet.h"
+
+class HingeJointBullet : public JointBullet {
+ class btHingeConstraint *hingeConstraint;
+
+public:
+ HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB);
+ HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB);
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_HINGE; }
+
+ real_t get_hinge_angle();
+
+ void set_param(PhysicsServer::HingeJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer::HingeJointParam p_param) const;
+
+ void set_flag(PhysicsServer::HingeJointFlag p_flag, bool p_value);
+ bool get_flag(PhysicsServer::HingeJointFlag p_flag) const;
+};
+#endif
diff --git a/modules/bullet/joint_bullet.cpp b/modules/bullet/joint_bullet.cpp
new file mode 100644
index 0000000000..be544f89bf
--- /dev/null
+++ b/modules/bullet/joint_bullet.cpp
@@ -0,0 +1,38 @@
+/*************************************************************************/
+/* joint_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "joint_bullet.h"
+#include "space_bullet.h"
+
+JointBullet::JointBullet()
+ : ConstraintBullet() {}
+
+JointBullet::~JointBullet() {}
diff --git a/modules/bullet/joint_bullet.h b/modules/bullet/joint_bullet.h
new file mode 100644
index 0000000000..d47e677502
--- /dev/null
+++ b/modules/bullet/joint_bullet.h
@@ -0,0 +1,49 @@
+/*************************************************************************/
+/* joint_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef JOINT_BULLET_H
+#define JOINT_BULLET_H
+
+#include "constraint_bullet.h"
+#include "servers/physics_server.h"
+
+class RigidBodyBullet;
+class btTypedConstraint;
+
+class JointBullet : public ConstraintBullet {
+
+public:
+ JointBullet();
+ virtual ~JointBullet();
+
+ virtual PhysicsServer::JointType get_type() const = 0;
+};
+#endif
diff --git a/modules/bullet/pin_joint_bullet.cpp b/modules/bullet/pin_joint_bullet.cpp
new file mode 100644
index 0000000000..cd9e9a4557
--- /dev/null
+++ b/modules/bullet/pin_joint_bullet.cpp
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* pin_joint_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "pin_joint_bullet.h"
+#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h"
+#include "bullet_types_converter.h"
+#include "rigid_body_bullet.h"
+
+PinJointBullet::PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b)
+ : JointBullet() {
+ if (p_body_b) {
+
+ btVector3 btPivotA;
+ btVector3 btPivotB;
+ G_TO_B(p_pos_a, btPivotA);
+ G_TO_B(p_pos_b, btPivotB);
+ p2pConstraint = bulletnew(btPoint2PointConstraint(*p_body_a->get_bt_rigid_body(),
+ *p_body_b->get_bt_rigid_body(),
+ btPivotA,
+ btPivotB));
+ } else {
+ btVector3 btPivotA;
+ G_TO_B(p_pos_a, btPivotA);
+ p2pConstraint = bulletnew(btPoint2PointConstraint(*p_body_a->get_bt_rigid_body(), btPivotA));
+ }
+
+ setup(p2pConstraint);
+}
+
+PinJointBullet::~PinJointBullet() {}
+
+void PinJointBullet::set_param(PhysicsServer::PinJointParam p_param, real_t p_value) {
+ switch (p_param) {
+ case PhysicsServer::PIN_JOINT_BIAS:
+ p2pConstraint->m_setting.m_tau = p_value;
+ break;
+ case PhysicsServer::PIN_JOINT_DAMPING:
+ p2pConstraint->m_setting.m_damping = p_value;
+ break;
+ case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP:
+ p2pConstraint->m_setting.m_impulseClamp = p_value;
+ break;
+ }
+}
+
+real_t PinJointBullet::get_param(PhysicsServer::PinJointParam p_param) const {
+ switch (p_param) {
+ case PhysicsServer::PIN_JOINT_BIAS:
+ return p2pConstraint->m_setting.m_tau;
+ case PhysicsServer::PIN_JOINT_DAMPING:
+ return p2pConstraint->m_setting.m_damping;
+ case PhysicsServer::PIN_JOINT_IMPULSE_CLAMP:
+ return p2pConstraint->m_setting.m_impulseClamp;
+ default:
+ WARN_PRINTS("This get parameter is not supported");
+ return 0;
+ }
+}
+
+void PinJointBullet::setPivotInA(const Vector3 &p_pos) {
+ btVector3 btVec;
+ G_TO_B(p_pos, btVec);
+ p2pConstraint->setPivotA(btVec);
+}
+
+void PinJointBullet::setPivotInB(const Vector3 &p_pos) {
+ btVector3 btVec;
+ G_TO_B(p_pos, btVec);
+ p2pConstraint->setPivotB(btVec);
+}
+
+Vector3 PinJointBullet::getPivotInA() {
+ btVector3 vec = p2pConstraint->getPivotInA();
+ Vector3 gVec;
+ B_TO_G(vec, gVec);
+ return gVec;
+}
+
+Vector3 PinJointBullet::getPivotInB() {
+ btVector3 vec = p2pConstraint->getPivotInB();
+ Vector3 gVec;
+ B_TO_G(vec, gVec);
+ return gVec;
+}
diff --git a/modules/bullet/pin_joint_bullet.h b/modules/bullet/pin_joint_bullet.h
new file mode 100644
index 0000000000..3a0906bf83
--- /dev/null
+++ b/modules/bullet/pin_joint_bullet.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* pin_joint_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PIN_JOINT_BULLET_H
+#define PIN_JOINT_BULLET_H
+
+#include "joint_bullet.h"
+
+class RigidBodyBullet;
+
+class PinJointBullet : public JointBullet {
+ class btPoint2PointConstraint *p2pConstraint;
+
+public:
+ PinJointBullet(RigidBodyBullet *p_body_a, const Vector3 &p_pos_a, RigidBodyBullet *p_body_b, const Vector3 &p_pos_b);
+ ~PinJointBullet();
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_PIN; }
+
+ void set_param(PhysicsServer::PinJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer::PinJointParam p_param) const;
+
+ void setPivotInA(const Vector3 &p_pos);
+ void setPivotInB(const Vector3 &p_pos);
+
+ Vector3 getPivotInA();
+ Vector3 getPivotInB();
+};
+#endif
diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp
new file mode 100644
index 0000000000..1e697e7443
--- /dev/null
+++ b/modules/bullet/register_types.cpp
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* register_types.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "bullet_physics_server.h"
+#include "class_db.h"
+
+PhysicsServer *_createBulletPhysicsCallback() {
+ return memnew(BulletPhysicsServer);
+}
+
+void register_bullet_types() {
+
+ PhysicsServerManager::register_server("Bullet", &_createBulletPhysicsCallback);
+ PhysicsServerManager::set_default_server("Bullet", 1);
+}
+
+void unregister_bullet_types() {
+}
diff --git a/modules/bullet/register_types.h b/modules/bullet/register_types.h
new file mode 100644
index 0000000000..ca0683fa3b
--- /dev/null
+++ b/modules/bullet/register_types.h
@@ -0,0 +1,37 @@
+/*************************************************************************/
+/* register_types.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef REGISTER_BULLET_TYPES_H
+#define REGISTER_BULLET_TYPES_H
+
+void register_bullet_types();
+void unregister_bullet_types();
+#endif
diff --git a/modules/bullet/rid_bullet.h b/modules/bullet/rid_bullet.h
new file mode 100644
index 0000000000..da7517f246
--- /dev/null
+++ b/modules/bullet/rid_bullet.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* rid_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RID_BULLET_H
+#define RID_BULLET_H
+
+#include "core/rid.h"
+
+class BulletPhysicsServer;
+
+class RIDBullet : public RID_Data {
+ RID self;
+ BulletPhysicsServer *physicsServer;
+
+public:
+ _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; }
+ _FORCE_INLINE_ RID get_self() const { return self; }
+
+ _FORCE_INLINE_ void _set_physics_server(BulletPhysicsServer *p_physicsServer) { physicsServer = p_physicsServer; }
+ _FORCE_INLINE_ BulletPhysicsServer *get_physics_server() const { return physicsServer; }
+};
+#endif
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
new file mode 100644
index 0000000000..5d0513db76
--- /dev/null
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -0,0 +1,1009 @@
+/*************************************************************************/
+/* body_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "rigid_body_bullet.h"
+#include "BulletCollision/CollisionDispatch/btGhostObject.h"
+#include "BulletCollision/CollisionShapes/btConvexPointCloudShape.h"
+#include "BulletDynamics/Dynamics/btRigidBody.h"
+#include "btBulletCollisionCommon.h"
+#include "btRayShape.h"
+#include "bullet_physics_server.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "godot_motion_state.h"
+#include "joint_bullet.h"
+#include <assert.h>
+
+BulletPhysicsDirectBodyState *BulletPhysicsDirectBodyState::singleton = NULL;
+
+Vector3 BulletPhysicsDirectBodyState::get_total_gravity() const {
+ Vector3 gVec;
+ B_TO_G(body->btBody->getGravity(), gVec);
+ return gVec;
+}
+
+float BulletPhysicsDirectBodyState::get_total_angular_damp() const {
+ return body->btBody->getAngularDamping();
+}
+
+float BulletPhysicsDirectBodyState::get_total_linear_damp() const {
+ return body->btBody->getLinearDamping();
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_center_of_mass() const {
+ Vector3 gVec;
+ B_TO_G(body->btBody->getCenterOfMassPosition(), gVec);
+ return gVec;
+}
+
+Basis BulletPhysicsDirectBodyState::get_principal_inertia_axes() const {
+ return Basis();
+}
+
+float BulletPhysicsDirectBodyState::get_inverse_mass() const {
+ return body->btBody->getInvMass();
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_inverse_inertia() const {
+ Vector3 gVec;
+ B_TO_G(body->btBody->getInvInertiaDiagLocal(), gVec);
+ return gVec;
+}
+
+Basis BulletPhysicsDirectBodyState::get_inverse_inertia_tensor() const {
+ Basis gInertia;
+ B_TO_G(body->btBody->getInvInertiaTensorWorld(), gInertia);
+ return gInertia;
+}
+
+void BulletPhysicsDirectBodyState::set_linear_velocity(const Vector3 &p_velocity) {
+ body->set_linear_velocity(p_velocity);
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_linear_velocity() const {
+ return body->get_linear_velocity();
+}
+
+void BulletPhysicsDirectBodyState::set_angular_velocity(const Vector3 &p_velocity) {
+ body->set_angular_velocity(p_velocity);
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_angular_velocity() const {
+ return body->get_angular_velocity();
+}
+
+void BulletPhysicsDirectBodyState::set_transform(const Transform &p_transform) {
+ body->set_transform(p_transform);
+}
+
+Transform BulletPhysicsDirectBodyState::get_transform() const {
+ return body->get_transform();
+}
+
+void BulletPhysicsDirectBodyState::add_force(const Vector3 &p_force, const Vector3 &p_pos) {
+ body->apply_force(p_force, p_pos);
+}
+
+void BulletPhysicsDirectBodyState::apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) {
+ body->apply_impulse(p_pos, p_j);
+}
+
+void BulletPhysicsDirectBodyState::apply_torque_impulse(const Vector3 &p_j) {
+ body->apply_torque_impulse(p_j);
+}
+
+void BulletPhysicsDirectBodyState::set_sleep_state(bool p_enable) {
+ body->set_activation_state(p_enable);
+}
+
+bool BulletPhysicsDirectBodyState::is_sleeping() const {
+ return !body->is_active();
+}
+
+int BulletPhysicsDirectBodyState::get_contact_count() const {
+ return body->collisionsCount;
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_contact_local_position(int p_contact_idx) const {
+ return body->collisions[p_contact_idx].hitLocalLocation;
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_contact_local_normal(int p_contact_idx) const {
+ return body->collisions[p_contact_idx].hitNormal;
+}
+
+int BulletPhysicsDirectBodyState::get_contact_local_shape(int p_contact_idx) const {
+ return body->collisions[p_contact_idx].local_shape;
+}
+
+RID BulletPhysicsDirectBodyState::get_contact_collider(int p_contact_idx) const {
+ return body->collisions[p_contact_idx].otherObject->get_self();
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_contact_collider_position(int p_contact_idx) const {
+ return body->collisions[p_contact_idx].hitWorldLocation;
+}
+
+ObjectID BulletPhysicsDirectBodyState::get_contact_collider_id(int p_contact_idx) const {
+ return body->collisions[p_contact_idx].otherObject->get_instance_id();
+}
+
+int BulletPhysicsDirectBodyState::get_contact_collider_shape(int p_contact_idx) const {
+ return body->collisions[p_contact_idx].other_object_shape;
+}
+
+Vector3 BulletPhysicsDirectBodyState::get_contact_collider_velocity_at_position(int p_contact_idx) const {
+ RigidBodyBullet::CollisionData &colDat = body->collisions[p_contact_idx];
+
+ btVector3 hitLocation;
+ G_TO_B(colDat.hitLocalLocation, hitLocation);
+
+ Vector3 velocityAtPoint;
+ B_TO_G(colDat.otherObject->get_bt_rigid_body()->getVelocityInLocalPoint(hitLocation), velocityAtPoint);
+
+ return velocityAtPoint;
+}
+
+PhysicsDirectSpaceState *BulletPhysicsDirectBodyState::get_space_state() {
+ return body->get_space()->get_direct_state();
+}
+
+RigidBodyBullet::KinematicUtilities::KinematicUtilities(RigidBodyBullet *p_owner)
+ : m_owner(p_owner), m_margin(0.01) // Godot default margin 0.001
+{
+ m_ghostObject = bulletnew(btPairCachingGhostObject);
+
+ int clearedCurrentFlags = m_ghostObject->getCollisionFlags();
+ clearedCurrentFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT);
+
+ m_ghostObject->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_KINEMATIC_OBJECT);
+ m_ghostObject->setUserPointer(p_owner);
+ m_ghostObject->setUserIndex(TYPE_KINEMATIC_GHOST_BODY);
+
+ resetDefShape();
+}
+
+RigidBodyBullet::KinematicUtilities::~KinematicUtilities() {
+ just_delete_shapes(m_shapes.size()); // don't need to resize
+ bulletdelete(m_ghostObject);
+}
+
+void RigidBodyBullet::KinematicUtilities::resetDefShape() {
+ m_ghostObject->setCollisionShape(BulletPhysicsServer::get_empty_shape());
+}
+
+void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() {
+ const Vector<CollisionObjectBullet::ShapeWrapper> &shapes_wrappers(m_owner->get_shapes_wrappers());
+ const int shapes_count = shapes_wrappers.size();
+
+ just_delete_shapes(shapes_count);
+
+ const CollisionObjectBullet::ShapeWrapper *shape_wrapper;
+
+ for (int i = shapes_count - 1; 0 <= i; --i) {
+ shape_wrapper = &shapes_wrappers[i];
+ if (!shape_wrapper->active) {
+ continue;
+ }
+ m_shapes[i].transform = shape_wrapper->transform;
+
+ btConvexShape *&kin_shape_ref = m_shapes[i].shape;
+
+ switch (shape_wrapper->shape->get_type()) {
+ case PhysicsServer::SHAPE_SPHERE: {
+ SphereShapeBullet *sphere = static_cast<SphereShapeBullet *>(shape_wrapper->shape);
+ kin_shape_ref = ShapeBullet::create_shape_sphere(sphere->get_radius() * m_owner->body_scale[0] + m_margin);
+ break;
+ }
+ case PhysicsServer::SHAPE_BOX: {
+ BoxShapeBullet *box = static_cast<BoxShapeBullet *>(shape_wrapper->shape);
+ kin_shape_ref = ShapeBullet::create_shape_box((box->get_half_extents() * m_owner->body_scale) + btVector3(m_margin, m_margin, m_margin));
+ break;
+ }
+ case PhysicsServer::SHAPE_CAPSULE: {
+ CapsuleShapeBullet *capsule = static_cast<CapsuleShapeBullet *>(shape_wrapper->shape);
+ kin_shape_ref = ShapeBullet::create_shape_capsule(capsule->get_radius() * m_owner->body_scale[0] + m_margin, capsule->get_height() * m_owner->body_scale[1] + m_margin);
+ break;
+ }
+ case PhysicsServer::SHAPE_CONVEX_POLYGON: {
+ ConvexPolygonShapeBullet *godot_convex = static_cast<ConvexPolygonShapeBullet *>(shape_wrapper->shape);
+ kin_shape_ref = ShapeBullet::create_shape_convex(godot_convex->vertices);
+ kin_shape_ref->setLocalScaling(m_owner->body_scale + btVector3(m_margin, m_margin, m_margin));
+ break;
+ }
+ case PhysicsServer::SHAPE_RAY: {
+ RayShapeBullet *godot_ray = static_cast<RayShapeBullet *>(shape_wrapper->shape);
+ kin_shape_ref = ShapeBullet::create_shape_ray(godot_ray->length * m_owner->body_scale[1] + m_margin);
+ break;
+ }
+ default:
+ WARN_PRINT("This shape is not supported to be kinematic!");
+ kin_shape_ref = NULL;
+ }
+ }
+}
+
+void RigidBodyBullet::KinematicUtilities::just_delete_shapes(int new_size) {
+ for (int i = m_shapes.size() - 1; 0 <= i; --i) {
+ if (m_shapes[i].shape) {
+ bulletdelete(m_shapes[i].shape);
+ }
+ }
+ m_shapes.resize(new_size);
+}
+
+RigidBodyBullet::RigidBodyBullet()
+ : RigidCollisionObjectBullet(CollisionObjectBullet::TYPE_RIGID_BODY),
+ kinematic_utilities(NULL),
+ gravity_scale(1),
+ mass(1),
+ linearDamp(0),
+ angularDamp(0),
+ can_sleep(true),
+ force_integration_callback(NULL),
+ isTransformChanged(false),
+ maxCollisionsDetection(0),
+ collisionsCount(0),
+ maxAreasWhereIam(10),
+ areaWhereIamCount(0),
+ countGravityPointSpaces(0),
+ isScratchedSpaceOverrideModificator(false) {
+
+ godotMotionState = bulletnew(GodotMotionState(this));
+
+ // Initial properties
+ const btVector3 localInertia(0, 0, 0);
+ btRigidBody::btRigidBodyConstructionInfo cInfo(mass, godotMotionState, compoundShape, localInertia);
+
+ btBody = bulletnew(btRigidBody(cInfo));
+ setupBulletCollisionObject(btBody);
+
+ set_mode(PhysicsServer::BODY_MODE_RIGID);
+ set_axis_lock(PhysicsServer::BODY_AXIS_LOCK_DISABLED);
+
+ areasWhereIam.resize(maxAreasWhereIam);
+ for (int i = areasWhereIam.size() - 1; 0 <= i; --i) {
+ areasWhereIam[i] = NULL;
+ }
+}
+
+RigidBodyBullet::~RigidBodyBullet() {
+ bulletdelete(godotMotionState);
+
+ if (force_integration_callback)
+ memdelete(force_integration_callback);
+
+ destroy_kinematic_utilities();
+}
+
+void RigidBodyBullet::init_kinematic_utilities() {
+ kinematic_utilities = memnew(KinematicUtilities(this));
+}
+
+void RigidBodyBullet::destroy_kinematic_utilities() {
+ if (kinematic_utilities) {
+ memdelete(kinematic_utilities);
+ kinematic_utilities = NULL;
+ }
+}
+
+void RigidBodyBullet::reload_body() {
+ if (space) {
+ space->remove_rigid_body(this);
+ space->add_rigid_body(this);
+ }
+}
+
+void RigidBodyBullet::set_space(SpaceBullet *p_space) {
+ // Clear the old space if there is one
+ if (space) {
+ isTransformChanged = false;
+
+ // Remove all eventual constraints
+ assert_no_constraints();
+
+ // Remove this object form the physics world
+ space->remove_rigid_body(this);
+ }
+
+ space = p_space;
+
+ if (space) {
+ space->add_rigid_body(this);
+ }
+}
+
+void RigidBodyBullet::dispatch_callbacks() {
+ /// The check isTransformChanged is necessary in order to call integrated forces only when the first transform is sent
+ if (btBody->isActive() && force_integration_callback && isTransformChanged) {
+
+ BulletPhysicsDirectBodyState *bodyDirect = BulletPhysicsDirectBodyState::get_singleton(this);
+
+ Variant variantBodyDirect = bodyDirect;
+
+ Object *obj = ObjectDB::get_instance(force_integration_callback->id);
+ if (!obj) {
+ // Remove integration callback
+ set_force_integration_callback(0, StringName());
+ } else {
+ const Variant *vp[2] = { &variantBodyDirect, &force_integration_callback->udata };
+
+ Variant::CallError responseCallError;
+ int argc = (force_integration_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
+ obj->call(force_integration_callback->method, vp, argc, responseCallError);
+ }
+ }
+
+ if (isScratchedSpaceOverrideModificator || 0 < countGravityPointSpaces) {
+ isScratchedSpaceOverrideModificator = false;
+ reload_space_override_modificator();
+ }
+
+ /// Lock axis
+ btBody->setLinearVelocity(btBody->getLinearVelocity() * btBody->getLinearFactor());
+ btBody->setAngularVelocity(btBody->getAngularVelocity() * btBody->getAngularFactor());
+}
+
+void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+
+ if (force_integration_callback) {
+ memdelete(force_integration_callback);
+ force_integration_callback = NULL;
+ }
+
+ if (p_id != 0) {
+ force_integration_callback = memnew(ForceIntegrationCallback);
+ force_integration_callback->id = p_id;
+ force_integration_callback->method = p_method;
+ force_integration_callback->udata = p_udata;
+ }
+}
+
+void RigidBodyBullet::scratch() {
+ isTransformChanged = true;
+}
+
+void RigidBodyBullet::scratch_space_override_modificator() {
+ isScratchedSpaceOverrideModificator = true;
+}
+
+void RigidBodyBullet::on_collision_filters_change() {
+ if (space) {
+ space->reload_collision_filters(this);
+ }
+}
+
+void RigidBodyBullet::on_collision_checker_start() {
+ collisionsCount = 0;
+}
+
+bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, int p_other_shape_index, int p_local_shape_index) {
+
+ if (collisionsCount >= maxCollisionsDetection) {
+ return false;
+ }
+
+ CollisionData &cd = collisions[collisionsCount];
+ cd.hitLocalLocation = p_hitLocalLocation;
+ cd.otherObject = p_otherObject;
+ cd.hitWorldLocation = p_hitWorldLocation;
+ cd.hitNormal = p_hitNormal;
+ cd.other_object_shape = p_other_shape_index;
+ cd.local_shape = p_local_shape_index;
+
+ ++collisionsCount;
+ return true;
+}
+
+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.");
+ }
+ /*for(int i = btBody->getNumConstraintRefs()-1; 0<=i; --i){
+ btTypedConstraint* btConst = btBody->getConstraintRef(i);
+ JointBullet* joint = static_cast<JointBullet*>( btConst->getUserConstraintPtr() );
+ space->removeConstraint(joint);
+ }*/
+}
+
+void RigidBodyBullet::set_activation_state(bool p_active) {
+ if (p_active) {
+ btBody->setActivationState(ACTIVE_TAG);
+ } else {
+ btBody->setActivationState(WANTS_DEACTIVATION);
+ }
+}
+
+bool RigidBodyBullet::is_active() const {
+ return btBody->isActive();
+}
+
+void RigidBodyBullet::set_param(PhysicsServer::BodyParameter p_param, real_t p_value) {
+ switch (p_param) {
+ case PhysicsServer::BODY_PARAM_BOUNCE:
+ btBody->setRestitution(p_value);
+ break;
+ case PhysicsServer::BODY_PARAM_FRICTION:
+ btBody->setFriction(p_value);
+ break;
+ case PhysicsServer::BODY_PARAM_MASS: {
+ ERR_FAIL_COND(p_value < 0);
+ mass = p_value;
+ _internal_set_mass(p_value);
+ break;
+ }
+ case PhysicsServer::BODY_PARAM_LINEAR_DAMP:
+ linearDamp = p_value;
+ btBody->setDamping(linearDamp, angularDamp);
+ break;
+ case PhysicsServer::BODY_PARAM_ANGULAR_DAMP:
+ angularDamp = p_value;
+ btBody->setDamping(linearDamp, angularDamp);
+ break;
+ case PhysicsServer::BODY_PARAM_GRAVITY_SCALE:
+ gravity_scale = p_value;
+ /// The Bullet gravity will be is set by reload_space_override_modificator
+ scratch_space_override_modificator();
+ break;
+ default:
+ WARN_PRINTS("Parameter " + itos(p_param) + " not supported by bullet. Value: " + itos(p_value));
+ }
+}
+
+real_t RigidBodyBullet::get_param(PhysicsServer::BodyParameter p_param) const {
+ switch (p_param) {
+ case PhysicsServer::BODY_PARAM_BOUNCE:
+ return btBody->getRestitution();
+ case PhysicsServer::BODY_PARAM_FRICTION:
+ return btBody->getFriction();
+ case PhysicsServer::BODY_PARAM_MASS: {
+ const btScalar invMass = btBody->getInvMass();
+ return 0 == invMass ? 0 : 1 / invMass;
+ }
+ case PhysicsServer::BODY_PARAM_LINEAR_DAMP:
+ return linearDamp;
+ case PhysicsServer::BODY_PARAM_ANGULAR_DAMP:
+ return angularDamp;
+ case PhysicsServer::BODY_PARAM_GRAVITY_SCALE:
+ return gravity_scale;
+ default:
+ WARN_PRINTS("Parameter " + itos(p_param) + " not supported by bullet");
+ return 0;
+ }
+}
+
+void RigidBodyBullet::set_mode(PhysicsServer::BodyMode p_mode) {
+ // This is necessary to block force_integration untile next move
+ isTransformChanged = false;
+ destroy_kinematic_utilities();
+ // The mode change is relevant to its mass
+ switch (p_mode) {
+ case PhysicsServer::BODY_MODE_KINEMATIC:
+ mode = PhysicsServer::BODY_MODE_KINEMATIC;
+ set_axis_lock(axis_lock); // Reload axis lock
+ _internal_set_mass(0);
+ init_kinematic_utilities();
+ break;
+ case PhysicsServer::BODY_MODE_STATIC:
+ mode = PhysicsServer::BODY_MODE_STATIC;
+ set_axis_lock(axis_lock); // Reload axis lock
+ _internal_set_mass(0);
+ break;
+ case PhysicsServer::BODY_MODE_RIGID: {
+ mode = PhysicsServer::BODY_MODE_RIGID;
+ set_axis_lock(axis_lock); // Reload axis lock
+ _internal_set_mass(0 == mass ? 1 : mass);
+ break;
+ }
+ case PhysicsServer::BODY_MODE_CHARACTER: {
+ mode = PhysicsServer::BODY_MODE_CHARACTER;
+ set_axis_lock(axis_lock); // Reload axis lock
+ _internal_set_mass(0 == mass ? 1 : mass);
+ break;
+ }
+ }
+
+ btBody->setAngularVelocity(btVector3(0, 0, 0));
+ btBody->setLinearVelocity(btVector3(0, 0, 0));
+}
+PhysicsServer::BodyMode RigidBodyBullet::get_mode() const {
+ return mode;
+}
+
+void RigidBodyBullet::set_state(PhysicsServer::BodyState p_state, const Variant &p_variant) {
+
+ switch (p_state) {
+ case PhysicsServer::BODY_STATE_TRANSFORM:
+ set_transform(p_variant);
+ break;
+ case PhysicsServer::BODY_STATE_LINEAR_VELOCITY:
+ set_linear_velocity(p_variant);
+ break;
+ case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY:
+ set_angular_velocity(p_variant);
+ break;
+ case PhysicsServer::BODY_STATE_SLEEPING:
+ set_activation_state(!bool(p_variant));
+ break;
+ case PhysicsServer::BODY_STATE_CAN_SLEEP:
+ can_sleep = bool(p_variant);
+ if (!can_sleep) {
+ // Can't sleep
+ btBody->forceActivationState(DISABLE_DEACTIVATION);
+ }
+ break;
+ }
+}
+
+Variant RigidBodyBullet::get_state(PhysicsServer::BodyState p_state) const {
+ switch (p_state) {
+ case PhysicsServer::BODY_STATE_TRANSFORM:
+ return get_transform();
+ case PhysicsServer::BODY_STATE_LINEAR_VELOCITY:
+ return get_linear_velocity();
+ case PhysicsServer::BODY_STATE_ANGULAR_VELOCITY:
+ return get_angular_velocity();
+ case PhysicsServer::BODY_STATE_SLEEPING:
+ return !is_active();
+ case PhysicsServer::BODY_STATE_CAN_SLEEP:
+ return can_sleep;
+ default:
+ WARN_PRINTS("This state " + itos(p_state) + " is not supported by Bullet");
+ return Variant();
+ }
+}
+
+void RigidBodyBullet::apply_central_impulse(const Vector3 &p_impulse) {
+ btVector3 btImpu;
+ G_TO_B(p_impulse, btImpu);
+ btBody->activate();
+ btBody->applyCentralImpulse(btImpu);
+}
+
+void RigidBodyBullet::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
+ btVector3 btImpu;
+ btVector3 btPos;
+ G_TO_B(p_impulse, btImpu);
+ G_TO_B(p_pos, btPos);
+ btBody->activate();
+ btBody->applyImpulse(btImpu, btPos);
+}
+
+void RigidBodyBullet::apply_torque_impulse(const Vector3 &p_impulse) {
+ btVector3 btImp;
+ G_TO_B(p_impulse, btImp);
+ btBody->activate();
+ btBody->applyTorqueImpulse(btImp);
+}
+
+void RigidBodyBullet::apply_force(const Vector3 &p_force, const Vector3 &p_pos) {
+ btVector3 btForce;
+ btVector3 btPos;
+ G_TO_B(p_force, btForce);
+ G_TO_B(p_pos, btPos);
+ btBody->activate();
+ btBody->applyForce(btForce, btPos);
+}
+
+void RigidBodyBullet::apply_central_force(const Vector3 &p_force) {
+ btVector3 btForce;
+ G_TO_B(p_force, btForce);
+ btBody->activate();
+ btBody->applyCentralForce(btForce);
+}
+
+void RigidBodyBullet::apply_torque(const Vector3 &p_torque) {
+ btVector3 btTorq;
+ G_TO_B(p_torque, btTorq);
+ btBody->activate();
+ btBody->applyTorque(btTorq);
+}
+
+void RigidBodyBullet::set_applied_force(const Vector3 &p_force) {
+ btVector3 btVec = btBody->getTotalTorque();
+
+ btBody->activate();
+
+ btBody->clearForces();
+ btBody->applyTorque(btVec);
+
+ G_TO_B(p_force, btVec);
+ btBody->applyCentralForce(btVec);
+}
+
+Vector3 RigidBodyBullet::get_applied_force() const {
+ Vector3 gTotForc;
+ B_TO_G(btBody->getTotalForce(), gTotForc);
+ return gTotForc;
+}
+
+void RigidBodyBullet::set_applied_torque(const Vector3 &p_torque) {
+ btVector3 btVec = btBody->getTotalForce();
+
+ btBody->activate();
+
+ btBody->clearForces();
+ btBody->applyCentralForce(btVec);
+
+ G_TO_B(p_torque, btVec);
+ btBody->applyTorque(btVec);
+}
+
+Vector3 RigidBodyBullet::get_applied_torque() const {
+ Vector3 gTotTorq;
+ B_TO_G(btBody->getTotalTorque(), gTotTorq);
+ return gTotTorq;
+}
+
+void RigidBodyBullet::set_axis_lock(PhysicsServer::BodyAxisLock p_lock) {
+ axis_lock = p_lock;
+
+ if (PhysicsServer::BODY_AXIS_LOCK_DISABLED == axis_lock) {
+ btBody->setLinearFactor(btVector3(1., 1., 1.));
+ btBody->setAngularFactor(btVector3(1., 1., 1.));
+ } else if (PhysicsServer::BODY_AXIS_LOCK_X == axis_lock) {
+ btBody->setLinearFactor(btVector3(0., 1., 1.));
+ btBody->setAngularFactor(btVector3(1., 0., 0.));
+ } else if (PhysicsServer::BODY_AXIS_LOCK_Y == axis_lock) {
+ btBody->setLinearFactor(btVector3(1., 0., 1.));
+ btBody->setAngularFactor(btVector3(0., 1., 0.));
+ } else if (PhysicsServer::BODY_AXIS_LOCK_Z == axis_lock) {
+ btBody->setLinearFactor(btVector3(1., 1., 0.));
+ btBody->setAngularFactor(btVector3(0., 0., 1.));
+ }
+
+ if (PhysicsServer::BODY_MODE_CHARACTER == mode) {
+ /// When character lock angular
+ btBody->setAngularFactor(btVector3(0., 0., 0.));
+ }
+}
+
+PhysicsServer::BodyAxisLock RigidBodyBullet::get_axis_lock() const {
+ btVector3 vec = btBody->getLinearFactor();
+ if (0. == vec.x()) {
+ return PhysicsServer::BODY_AXIS_LOCK_X;
+ } else if (0. == vec.y()) {
+ return PhysicsServer::BODY_AXIS_LOCK_Y;
+ } else if (0. == vec.z()) {
+ return PhysicsServer::BODY_AXIS_LOCK_Z;
+ } else {
+ return PhysicsServer::BODY_AXIS_LOCK_DISABLED;
+ }
+}
+
+void RigidBodyBullet::set_continuous_collision_detection(bool p_enable) {
+ if (p_enable) {
+ // This threshold enable CCD if the object moves more than
+ // 1 meter in one simulation frame
+ btBody->setCcdMotionThreshold(1);
+
+ /// Calculate using the rule writte below the CCD swept sphere radius
+ /// CCD works on an embedded sphere of radius, make sure this radius
+ /// is embedded inside the convex objects, preferably smaller:
+ /// for an object of dimentions 1 meter, try 0.2
+ btVector3 center;
+ btScalar radius;
+ btBody->getCollisionShape()->getBoundingSphere(center, radius);
+ btBody->setCcdSweptSphereRadius(radius * 0.2);
+ } else {
+ btBody->setCcdMotionThreshold(0.);
+ btBody->setCcdSweptSphereRadius(0.);
+ }
+}
+
+bool RigidBodyBullet::is_continuous_collision_detection_enabled() const {
+ return 0. != btBody->getCcdMotionThreshold();
+}
+
+void RigidBodyBullet::set_linear_velocity(const Vector3 &p_velocity) {
+ btVector3 btVec;
+ G_TO_B(p_velocity, btVec);
+ btBody->activate();
+ btBody->setLinearVelocity(btVec);
+}
+
+Vector3 RigidBodyBullet::get_linear_velocity() const {
+ Vector3 gVec;
+ B_TO_G(btBody->getLinearVelocity(), gVec);
+ return gVec;
+}
+
+void RigidBodyBullet::set_angular_velocity(const Vector3 &p_velocity) {
+ btVector3 btVec;
+ G_TO_B(p_velocity, btVec);
+ btBody->activate();
+ btBody->setAngularVelocity(btVec);
+}
+
+Vector3 RigidBodyBullet::get_angular_velocity() const {
+ Vector3 gVec;
+ B_TO_G(btBody->getAngularVelocity(), gVec);
+ return gVec;
+}
+
+void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) {
+ if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
+ // The kinematic use MotionState class
+ godotMotionState->moveBody(p_global_transform);
+ }
+ btBody->setWorldTransform(p_global_transform);
+}
+
+const btTransform &RigidBodyBullet::get_transform__bullet() const {
+ if (is_static()) {
+
+ return RigidCollisionObjectBullet::get_transform__bullet();
+ } else {
+
+ return godotMotionState->getCurrentWorldTransform();
+ }
+}
+
+void RigidBodyBullet::on_shapes_changed() {
+ RigidCollisionObjectBullet::on_shapes_changed();
+
+ const btScalar invMass = btBody->getInvMass();
+ const btScalar mass = invMass == 0 ? 0 : 1 / invMass;
+
+ btVector3 inertia;
+ btBody->getCollisionShape()->calculateLocalInertia(mass, inertia);
+ btBody->setMassProps(mass, inertia);
+ btBody->updateInertiaTensor();
+
+ reload_kinematic_shapes();
+
+ reload_body();
+}
+
+void RigidBodyBullet::on_enter_area(AreaBullet *p_area) {
+ /// Add this area to the array in an ordered way
+ ++areaWhereIamCount;
+ if (areaWhereIamCount >= maxAreasWhereIam) {
+ --areaWhereIamCount;
+ return;
+ }
+ for (int i = 0; i < areaWhereIamCount; ++i) {
+
+ if (NULL == areasWhereIam[i]) {
+ // This area has the highest priority
+ areasWhereIam[i] = p_area;
+ break;
+ } else {
+ if (areasWhereIam[i]->get_spOv_priority() > p_area->get_spOv_priority()) {
+ // The position was found, just shift all elements
+ for (int j = i; j < areaWhereIamCount; ++j) {
+ areasWhereIam[j + 1] = areasWhereIam[j];
+ }
+ areasWhereIam[i] = p_area;
+ break;
+ }
+ }
+ }
+ if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) {
+ scratch_space_override_modificator();
+ }
+
+ if (p_area->is_spOv_gravityPoint()) {
+ ++countGravityPointSpaces;
+ assert(0 < countGravityPointSpaces);
+ }
+}
+
+void RigidBodyBullet::on_exit_area(AreaBullet *p_area) {
+ RigidCollisionObjectBullet::on_exit_area(p_area);
+ /// Remove this area and keep the order
+ /// N.B. Since I don't want resize the array I can't use the "erase" function
+ bool wasTheAreaFound = false;
+ for (int i = 0; i < areaWhereIamCount; ++i) {
+ if (p_area == areasWhereIam[i]) {
+ // The area was fount, just shift down all elements
+ for (int j = i; j < areaWhereIamCount; ++j) {
+ areasWhereIam[j] = areasWhereIam[j + 1];
+ }
+ wasTheAreaFound = true;
+ break;
+ }
+ }
+ if (wasTheAreaFound) {
+ if (p_area->is_spOv_gravityPoint()) {
+ --countGravityPointSpaces;
+ assert(0 <= countGravityPointSpaces);
+ }
+
+ --areaWhereIamCount;
+ areasWhereIam[areaWhereIamCount] = NULL; // Even if this is not required, I clear the last element to be safe
+ if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) {
+ scratch_space_override_modificator();
+ }
+ }
+}
+
+void RigidBodyBullet::reload_space_override_modificator() {
+
+ Vector3 newGravity(space->get_gravity_direction() * space->get_gravity_magnitude());
+ real_t newLinearDamp(linearDamp);
+ real_t newAngularDamp(angularDamp);
+
+ AreaBullet *currentArea;
+ // Variable used to calculate new gravity for gravity point areas, it is pointed by currentGravity pointer
+ Vector3 support_gravity(0, 0, 0);
+
+ int countCombined(0);
+ for (int i = areaWhereIamCount - 1; 0 <= i; --i) {
+
+ currentArea = areasWhereIam[i];
+
+ if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED == currentArea->get_spOv_mode()) {
+ continue;
+ }
+
+ /// Here is calculated the gravity
+ if (currentArea->is_spOv_gravityPoint()) {
+
+ /// It calculates the direction of new gravity
+ support_gravity = currentArea->get_transform().xform(currentArea->get_spOv_gravityVec()) - get_transform().get_origin();
+ real_t distanceMag = support_gravity.length();
+ // Normalized in this way to avoid the double call of function "length()"
+ if (distanceMag == 0) {
+ support_gravity.x = 0;
+ support_gravity.y = 0;
+ support_gravity.z = 0;
+ } else {
+ support_gravity.x /= distanceMag;
+ support_gravity.y /= distanceMag;
+ support_gravity.z /= distanceMag;
+ }
+
+ /// Here is calculated the final gravity
+ if (currentArea->get_spOv_gravityPointDistanceScale() > 0) {
+ // Scaled gravity by distance
+ support_gravity *= currentArea->get_spOv_gravityMag() / Math::pow(distanceMag * currentArea->get_spOv_gravityPointDistanceScale() + 1, 2);
+ } else {
+ // Unscaled gravity
+ support_gravity *= currentArea->get_spOv_gravityMag();
+ }
+ } else {
+ support_gravity = currentArea->get_spOv_gravityVec() * currentArea->get_spOv_gravityMag();
+ }
+
+ switch (currentArea->get_spOv_mode()) {
+ ///case PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED:
+ /// This area does not affect gravity/damp. These are generally areas
+ /// that exist only to detect collisions, and objects entering or exiting them.
+ /// break;
+ case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE:
+ /// This area adds its gravity/damp values to whatever has been
+ /// calculated so far. This way, many overlapping areas can combine
+ /// their physics to make interesting
+ newGravity += support_gravity;
+ newLinearDamp += currentArea->get_spOv_linearDamp();
+ newAngularDamp += currentArea->get_spOv_angularDamp();
+ ++countCombined;
+ break;
+ case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE:
+ /// This area adds its gravity/damp values to whatever has been calculated
+ /// so far. Then stops taking into account the rest of the areas, even the
+ /// default one.
+ newGravity += support_gravity;
+ newLinearDamp += currentArea->get_spOv_linearDamp();
+ newAngularDamp += currentArea->get_spOv_angularDamp();
+ ++countCombined;
+ goto endAreasCycle;
+ case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE:
+ /// This area replaces any gravity/damp, even the default one, and
+ /// stops taking into account the rest of the areas.
+ newGravity = support_gravity;
+ newLinearDamp = currentArea->get_spOv_linearDamp();
+ newAngularDamp = currentArea->get_spOv_angularDamp();
+ countCombined = 1;
+ goto endAreasCycle;
+ case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE:
+ /// This area replaces any gravity/damp calculated so far, but keeps
+ /// calculating the rest of the areas, down to the default one.
+ newGravity = support_gravity;
+ newLinearDamp = currentArea->get_spOv_linearDamp();
+ newAngularDamp = currentArea->get_spOv_angularDamp();
+ countCombined = 1;
+ break;
+ }
+ }
+endAreasCycle:
+
+ if (1 < countCombined) {
+ newGravity /= countCombined;
+ newLinearDamp /= countCombined;
+ newAngularDamp /= countCombined;
+ }
+
+ btVector3 newBtGravity;
+ G_TO_B(newGravity * gravity_scale, newBtGravity);
+
+ btBody->setGravity(newBtGravity);
+ btBody->setDamping(newLinearDamp, newAngularDamp);
+}
+
+void RigidBodyBullet::reload_kinematic_shapes() {
+ if (!kinematic_utilities) {
+ return;
+ }
+ kinematic_utilities->copyAllOwnerShapes();
+}
+
+void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
+
+ btVector3 localInertia(0, 0, 0);
+
+ int clearedCurrentFlags = btBody->getCollisionFlags();
+ clearedCurrentFlags &= ~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_CHARACTER_OBJECT);
+
+ // Rigidbody is dynamic if and only if mass is non Zero, otherwise static
+ const bool isDynamic = p_mass != 0.f;
+ if (isDynamic) {
+
+ ERR_FAIL_COND(PhysicsServer::BODY_MODE_RIGID != mode && PhysicsServer::BODY_MODE_CHARACTER != mode);
+
+ m_isStatic = false;
+ compoundShape->calculateLocalInertia(p_mass, localInertia);
+
+ if (PhysicsServer::BODY_MODE_RIGID == mode) {
+
+ btBody->setCollisionFlags(clearedCurrentFlags); // Just set the flags without Kin and Static
+ } else {
+
+ btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_CHARACTER_OBJECT);
+ }
+
+ if (can_sleep) {
+ btBody->forceActivationState(ACTIVE_TAG); // ACTIVE_TAG 1
+ } else {
+ btBody->forceActivationState(DISABLE_DEACTIVATION); // DISABLE_DEACTIVATION 4
+ }
+ } else {
+
+ ERR_FAIL_COND(PhysicsServer::BODY_MODE_STATIC != mode && PhysicsServer::BODY_MODE_KINEMATIC != mode);
+
+ m_isStatic = true;
+ if (PhysicsServer::BODY_MODE_STATIC == mode) {
+
+ btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_STATIC_OBJECT);
+ } else {
+
+ btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_KINEMATIC_OBJECT);
+ set_transform__bullet(btBody->getWorldTransform()); // Set current Transform using kinematic method
+ }
+ btBody->forceActivationState(DISABLE_SIMULATION); // DISABLE_SIMULATION 5
+ }
+
+ btBody->setMassProps(p_mass, localInertia);
+ btBody->updateInertiaTensor();
+
+ reload_body();
+}
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
new file mode 100644
index 0000000000..0cf3f9f605
--- /dev/null
+++ b/modules/bullet/rigid_body_bullet.h
@@ -0,0 +1,304 @@
+/*************************************************************************/
+/* body_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef BODYBULLET_H
+#define BODYBULLET_H
+
+#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
+#include "LinearMath/btTransform.h"
+#include "collision_object_bullet.h"
+#include "space_bullet.h"
+
+class AreaBullet;
+class SpaceBullet;
+class btRigidBody;
+class GodotMotionState;
+class BulletPhysicsDirectBodyState;
+
+/// This class could be used in multi thread with few changes but currently
+/// is setted to be only in one single thread.
+///
+/// In the system there is only one object at a time that manage all bodies and is
+/// created by BulletPhysicsServer and is held by the "singleton" variable of this class
+/// Each time something require it, the body must be setted again.
+class BulletPhysicsDirectBodyState : public PhysicsDirectBodyState {
+ GDCLASS(BulletPhysicsDirectBodyState, PhysicsDirectBodyState)
+
+ static BulletPhysicsDirectBodyState *singleton;
+
+public:
+ /// This class avoid the creation of more object of this class
+ static void initSingleton() {
+ if (!singleton) {
+ singleton = memnew(BulletPhysicsDirectBodyState);
+ }
+ }
+
+ static void destroySingleton() {
+ memdelete(singleton);
+ singleton = NULL;
+ }
+
+ static void singleton_setDeltaTime(real_t p_deltaTime) {
+ singleton->deltaTime = p_deltaTime;
+ }
+
+ static BulletPhysicsDirectBodyState *get_singleton(RigidBodyBullet *p_body) {
+ singleton->body = p_body;
+ return singleton;
+ }
+
+public:
+ RigidBodyBullet *body;
+ real_t deltaTime;
+
+private:
+ BulletPhysicsDirectBodyState() {}
+
+public:
+ virtual Vector3 get_total_gravity() const;
+ virtual float get_total_angular_damp() const;
+ virtual float get_total_linear_damp() const;
+
+ virtual Vector3 get_center_of_mass() const;
+ virtual Basis get_principal_inertia_axes() const;
+ // get the mass
+ virtual float get_inverse_mass() const;
+ // get density of this body space
+ virtual Vector3 get_inverse_inertia() const;
+ // get density of this body space
+ virtual Basis get_inverse_inertia_tensor() const;
+
+ virtual void set_linear_velocity(const Vector3 &p_velocity);
+ virtual Vector3 get_linear_velocity() const;
+
+ virtual void set_angular_velocity(const Vector3 &p_velocity);
+ virtual Vector3 get_angular_velocity() const;
+
+ virtual void set_transform(const Transform &p_transform);
+ virtual Transform get_transform() const;
+
+ virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos);
+ virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j);
+ virtual void apply_torque_impulse(const Vector3 &p_j);
+
+ virtual void set_sleep_state(bool p_enable);
+ virtual bool is_sleeping() const;
+
+ virtual int get_contact_count() const;
+
+ virtual Vector3 get_contact_local_position(int p_contact_idx) const;
+ virtual Vector3 get_contact_local_normal(int p_contact_idx) const;
+ virtual int get_contact_local_shape(int p_contact_idx) const;
+
+ virtual RID get_contact_collider(int p_contact_idx) const;
+ virtual Vector3 get_contact_collider_position(int p_contact_idx) const;
+ virtual ObjectID get_contact_collider_id(int p_contact_idx) const;
+ virtual int get_contact_collider_shape(int p_contact_idx) const;
+ virtual Vector3 get_contact_collider_velocity_at_position(int p_contact_idx) const;
+
+ virtual real_t get_step() const { return deltaTime; }
+ virtual void integrate_forces() {
+ // Skip the execution of this function
+ }
+
+ virtual PhysicsDirectSpaceState *get_space_state();
+};
+
+class RigidBodyBullet : public RigidCollisionObjectBullet {
+
+public:
+ struct CollisionData {
+ RigidBodyBullet *otherObject;
+ int other_object_shape;
+ int local_shape;
+ Vector3 hitLocalLocation;
+ Vector3 hitWorldLocation;
+ Vector3 hitNormal;
+ };
+
+ struct ForceIntegrationCallback {
+ ObjectID id;
+ StringName method;
+ Variant udata;
+ };
+
+ /// Used to hold shapes
+ struct KinematicShape {
+ class btConvexShape *shape;
+ btTransform transform;
+
+ KinematicShape()
+ : shape(NULL) {}
+ const bool is_active() const { return shape; }
+ };
+
+ struct KinematicUtilities {
+ RigidBodyBullet *m_owner;
+ btScalar m_margin;
+ btManifoldArray m_manifoldArray; ///keep track of the contact manifolds
+ class btPairCachingGhostObject *m_ghostObject;
+ Vector<KinematicShape> m_shapes;
+
+ KinematicUtilities(RigidBodyBullet *p_owner);
+ ~KinematicUtilities();
+
+ /// Used to set the default shape to ghost
+ void resetDefShape();
+ void copyAllOwnerShapes();
+
+ private:
+ void just_delete_shapes(int new_size);
+ };
+
+private:
+ friend class BulletPhysicsDirectBodyState;
+
+ // This is required only for Kinematic movement
+ KinematicUtilities *kinematic_utilities;
+
+ PhysicsServer::BodyMode mode;
+ PhysicsServer::BodyAxisLock axis_lock;
+ GodotMotionState *godotMotionState;
+ btRigidBody *btBody;
+ real_t mass;
+ real_t gravity_scale;
+ real_t linearDamp;
+ real_t angularDamp;
+ bool can_sleep;
+
+ Vector<CollisionData> collisions;
+ // these parameters are used to avoid vector resize
+ int maxCollisionsDetection;
+ int collisionsCount;
+
+ Vector<AreaBullet *> areasWhereIam;
+ // these parameters are used to avoid vector resize
+ int maxAreasWhereIam;
+ int areaWhereIamCount;
+ // Used to know if the area is used as gravity point
+ int countGravityPointSpaces;
+ bool isScratchedSpaceOverrideModificator;
+
+ bool isTransformChanged;
+
+ ForceIntegrationCallback *force_integration_callback;
+
+public:
+ RigidBodyBullet();
+ ~RigidBodyBullet();
+
+ void init_kinematic_utilities();
+ void destroy_kinematic_utilities();
+ _FORCE_INLINE_ class KinematicUtilities *get_kinematic_utilities() const { return kinematic_utilities; }
+
+ _FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; }
+
+ virtual void reload_body();
+ virtual void set_space(SpaceBullet *p_space);
+
+ virtual void dispatch_callbacks();
+ void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void scratch();
+ void scratch_space_override_modificator();
+
+ virtual void on_collision_filters_change();
+ virtual void on_collision_checker_start();
+ void set_max_collisions_detection(int p_maxCollisionsDetection) {
+ maxCollisionsDetection = p_maxCollisionsDetection;
+ collisions.resize(p_maxCollisionsDetection);
+ collisionsCount = 0;
+ }
+ int get_max_collisions_detection() {
+ return maxCollisionsDetection;
+ }
+
+ 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, int p_other_shape_index, int p_local_shape_index);
+
+ void assert_no_constraints();
+
+ void set_activation_state(bool p_active);
+ bool is_active() const;
+
+ void set_param(PhysicsServer::BodyParameter p_param, real_t);
+ real_t get_param(PhysicsServer::BodyParameter p_param) const;
+
+ void set_mode(PhysicsServer::BodyMode p_mode);
+ PhysicsServer::BodyMode get_mode() const;
+
+ void set_state(PhysicsServer::BodyState p_state, const Variant &p_variant);
+ Variant get_state(PhysicsServer::BodyState p_state) const;
+
+ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
+ void apply_central_impulse(const Vector3 &p_force);
+ void apply_torque_impulse(const Vector3 &p_impulse);
+
+ void apply_force(const Vector3 &p_force, const Vector3 &p_pos);
+ void apply_central_force(const Vector3 &p_force);
+ void apply_torque(const Vector3 &p_force);
+
+ void set_applied_force(const Vector3 &p_force);
+ Vector3 get_applied_force() const;
+ void set_applied_torque(const Vector3 &p_torque);
+ Vector3 get_applied_torque() const;
+
+ void set_axis_lock(PhysicsServer::BodyAxisLock p_lock);
+ PhysicsServer::BodyAxisLock get_axis_lock() const;
+
+ /// Doc:
+ /// http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Anti_tunneling_by_Motion_Clamping
+ void set_continuous_collision_detection(bool p_enable);
+ bool is_continuous_collision_detection_enabled() const;
+
+ void set_linear_velocity(const Vector3 &p_velocity);
+ Vector3 get_linear_velocity() const;
+
+ void set_angular_velocity(const Vector3 &p_velocity);
+ Vector3 get_angular_velocity() const;
+
+ virtual void set_transform__bullet(const btTransform &p_global_transform);
+ virtual const btTransform &get_transform__bullet() const;
+
+ virtual void on_shapes_changed();
+
+ virtual void on_enter_area(AreaBullet *p_area);
+ virtual void on_exit_area(AreaBullet *p_area);
+ void reload_space_override_modificator();
+
+ /// Kinematic
+ void reload_kinematic_shapes();
+
+private:
+ void _internal_set_mass(real_t p_mass);
+};
+
+#endif
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
new file mode 100644
index 0000000000..49150484d9
--- /dev/null
+++ b/modules/bullet/shape_bullet.cpp
@@ -0,0 +1,435 @@
+/*************************************************************************/
+/* shape_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "shape_bullet.h"
+#include "BulletCollision/CollisionShapes/btConvexPointCloudShape.h"
+#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
+#include "btBulletCollisionCommon.h"
+#include "btRayShape.h"
+#include "bullet_physics_server.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "shape_owner_bullet.h"
+
+ShapeBullet::ShapeBullet() {}
+
+ShapeBullet::~ShapeBullet() {}
+
+btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
+ p_btShape->setUserPointer(const_cast<ShapeBullet *>(this));
+ return p_btShape;
+}
+
+void ShapeBullet::notifyShapeChanged() {
+ for (Map<ShapeOwnerBullet *, int>::Element *E = owners.front(); E; E = E->next()) {
+ static_cast<ShapeOwnerBullet *>(E->key())->on_shape_changed(this);
+ }
+}
+
+void ShapeBullet::add_owner(ShapeOwnerBullet *p_owner) {
+ Map<ShapeOwnerBullet *, int>::Element *E = owners.find(p_owner);
+ if (E) {
+ E->get()++;
+ } else {
+ owners[p_owner] = 1; // add new owner
+ }
+}
+
+void ShapeBullet::remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody) {
+ Map<ShapeOwnerBullet *, int>::Element *E = owners.find(p_owner);
+ ERR_FAIL_COND(!E);
+ E->get()--;
+ if (p_permanentlyFromThisBody || 0 >= E->get()) {
+ owners.erase(E);
+ }
+}
+
+bool ShapeBullet::is_owner(ShapeOwnerBullet *p_owner) const {
+
+ return owners.has(p_owner);
+}
+
+const Map<ShapeOwnerBullet *, int> &ShapeBullet::get_owners() const {
+ return owners;
+}
+
+btEmptyShape *ShapeBullet::create_shape_empty() {
+ return bulletnew(btEmptyShape);
+}
+
+btStaticPlaneShape *ShapeBullet::create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant) {
+ return bulletnew(btStaticPlaneShape(planeNormal, planeConstant));
+}
+
+btSphereShape *ShapeBullet::create_shape_sphere(btScalar radius) {
+ return bulletnew(btSphereShape(radius));
+}
+
+btBoxShape *ShapeBullet::create_shape_box(const btVector3 &boxHalfExtents) {
+ return bulletnew(btBoxShape(boxHalfExtents));
+}
+
+btCapsuleShapeZ *ShapeBullet::create_shape_capsule(btScalar radius, btScalar height) {
+ return bulletnew(btCapsuleShapeZ(radius, height));
+}
+
+btConvexPointCloudShape *ShapeBullet::create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling) {
+ return bulletnew(btConvexPointCloudShape(&p_vertices[0], p_vertices.size(), p_local_scaling));
+}
+
+btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling) {
+ if (p_mesh_shape) {
+ return bulletnew(btScaledBvhTriangleMeshShape(p_mesh_shape, p_local_scaling));
+ } else {
+ return NULL;
+ }
+}
+
+btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) {
+ const btScalar ignoredHeightScale(1);
+ const btScalar fieldHeight(500); // Meters
+ const int YAxis = 1; // 0=X, 1=Y, 2=Z
+ const bool flipQuadEdges = false;
+ const void *heightsPtr = p_heights.read().ptr();
+
+ return bulletnew(btHeightfieldTerrainShape(p_width, p_depth, heightsPtr, ignoredHeightScale, -fieldHeight, fieldHeight, YAxis, PHY_FLOAT, flipQuadEdges));
+}
+
+btRayShape *ShapeBullet::create_shape_ray(real_t p_length) {
+ return bulletnew(btRayShape(p_length));
+}
+
+/* PLANE */
+
+PlaneShapeBullet::PlaneShapeBullet()
+ : ShapeBullet() {}
+
+void PlaneShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant PlaneShapeBullet::get_data() const {
+ return plane;
+}
+
+PhysicsServer::ShapeType PlaneShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_PLANE;
+}
+
+void PlaneShapeBullet::setup(const Plane &p_plane) {
+ plane = p_plane;
+ notifyShapeChanged();
+}
+
+btCollisionShape *PlaneShapeBullet::create_bt_shape() {
+ btVector3 btPlaneNormal;
+ G_TO_B(plane.normal, btPlaneNormal);
+ return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d));
+}
+
+/* Sphere */
+
+SphereShapeBullet::SphereShapeBullet()
+ : ShapeBullet() {}
+
+void SphereShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant SphereShapeBullet::get_data() const {
+ return radius;
+}
+
+PhysicsServer::ShapeType SphereShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_SPHERE;
+}
+
+void SphereShapeBullet::setup(real_t p_radius) {
+ radius = p_radius;
+ notifyShapeChanged();
+}
+
+btCollisionShape *SphereShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_sphere(radius));
+}
+
+/* Box */
+BoxShapeBullet::BoxShapeBullet()
+ : ShapeBullet() {}
+
+void BoxShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant BoxShapeBullet::get_data() const {
+ Vector3 g_half_extents;
+ B_TO_G(half_extents, g_half_extents);
+ return g_half_extents;
+}
+
+PhysicsServer::ShapeType BoxShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_BOX;
+}
+
+void BoxShapeBullet::setup(const Vector3 &p_half_extents) {
+ G_TO_B(p_half_extents, half_extents);
+ notifyShapeChanged();
+}
+
+btCollisionShape *BoxShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_box(half_extents));
+}
+
+/* Capsule */
+
+CapsuleShapeBullet::CapsuleShapeBullet()
+ : ShapeBullet() {}
+
+void CapsuleShapeBullet::set_data(const Variant &p_data) {
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("radius"));
+ ERR_FAIL_COND(!d.has("height"));
+ setup(d["height"], d["radius"]);
+}
+
+Variant CapsuleShapeBullet::get_data() const {
+ Dictionary d;
+ d["radius"] = radius;
+ d["height"] = height;
+ return d;
+}
+
+PhysicsServer::ShapeType CapsuleShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_CAPSULE;
+}
+
+void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) {
+ radius = p_radius;
+ height = p_height;
+ notifyShapeChanged();
+}
+
+btCollisionShape *CapsuleShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_capsule(radius, height));
+}
+
+/* Convex polygon */
+
+ConvexPolygonShapeBullet::ConvexPolygonShapeBullet()
+ : ShapeBullet() {}
+
+void ConvexPolygonShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+void ConvexPolygonShapeBullet::get_vertices(Vector<Vector3> &out_vertices) {
+ const int n_of_vertices = vertices.size();
+ out_vertices.resize(n_of_vertices);
+ for (int i = n_of_vertices - 1; 0 <= i; --i) {
+ B_TO_G(vertices[i], out_vertices[i]);
+ }
+}
+
+Variant ConvexPolygonShapeBullet::get_data() const {
+ ConvexPolygonShapeBullet *variable_self = const_cast<ConvexPolygonShapeBullet *>(this);
+ Vector<Vector3> out_vertices;
+ variable_self->get_vertices(out_vertices);
+ return out_vertices;
+}
+
+PhysicsServer::ShapeType ConvexPolygonShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_CONVEX_POLYGON;
+}
+
+void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) {
+ // Make a copy of verticies
+ const int n_of_vertices = p_vertices.size();
+ vertices.resize(n_of_vertices);
+ for (int i = n_of_vertices - 1; 0 <= i; --i) {
+ G_TO_B(p_vertices[i], vertices[i]);
+ }
+ notifyShapeChanged();
+}
+
+btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_convex(vertices));
+}
+
+/* Concave polygon */
+
+ConcavePolygonShapeBullet::ConcavePolygonShapeBullet()
+ : ShapeBullet(), meshShape(NULL) {}
+
+ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() {
+ if (meshShape) {
+ delete meshShape->getMeshInterface();
+ delete meshShape;
+ }
+ faces = PoolVector<Vector3>();
+}
+
+void ConcavePolygonShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant ConcavePolygonShapeBullet::get_data() const {
+ return faces;
+}
+
+PhysicsServer::ShapeType ConcavePolygonShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_CONCAVE_POLYGON;
+}
+
+void ConcavePolygonShapeBullet::setup(PoolVector<Vector3> p_faces) {
+ faces = p_faces;
+ if (meshShape) {
+ /// Clear previous created shape
+ delete meshShape->getMeshInterface();
+ bulletdelete(meshShape);
+ }
+ int src_face_count = faces.size();
+ if (0 < src_face_count) {
+
+ btTriangleMesh *shapeInterface = bulletnew(btTriangleMesh);
+
+ // It counts the faces and assert the array contains the correct number of vertices.
+ ERR_FAIL_COND(src_face_count % 3);
+ src_face_count /= 3;
+ PoolVector<Vector3>::Read r = p_faces.read();
+ const Vector3 *facesr = r.ptr();
+
+ btVector3 supVec_0;
+ btVector3 supVec_1;
+ btVector3 supVec_2;
+ for (int i = 0; i < src_face_count; ++i) {
+ G_TO_B(facesr[i * 3], supVec_0);
+ G_TO_B(facesr[i * 3 + 1], supVec_1);
+ G_TO_B(facesr[i * 3 + 2], supVec_2);
+
+ shapeInterface->addTriangle(supVec_0, supVec_1, supVec_2);
+ }
+
+ const bool useQuantizedAabbCompression = true;
+
+ meshShape = bulletnew(btBvhTriangleMeshShape(shapeInterface, useQuantizedAabbCompression));
+ } else {
+ meshShape = NULL;
+ ERR_PRINT("The faces count are 0, the mesh shape cannot be created");
+ }
+ notifyShapeChanged();
+}
+
+btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape() {
+ btCollisionShape *cs = ShapeBullet::create_shape_concave(meshShape);
+ if (!cs) {
+ // This is necessary since if 0 faces the creation of concave return NULL
+ cs = ShapeBullet::create_shape_empty();
+ }
+ return prepare(cs);
+}
+
+/* Height map shape */
+
+HeightMapShapeBullet::HeightMapShapeBullet()
+ : ShapeBullet() {}
+
+void HeightMapShapeBullet::set_data(const Variant &p_data) {
+ ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY);
+ Dictionary d = p_data;
+ ERR_FAIL_COND(!d.has("width"));
+ ERR_FAIL_COND(!d.has("depth"));
+ ERR_FAIL_COND(!d.has("cell_size"));
+ ERR_FAIL_COND(!d.has("heights"));
+
+ int l_width = d["width"];
+ int l_depth = d["depth"];
+ real_t l_cell_size = d["cell_size"];
+ PoolVector<real_t> l_heights = d["heights"];
+
+ ERR_FAIL_COND(l_width <= 0);
+ ERR_FAIL_COND(l_depth <= 0);
+ ERR_FAIL_COND(l_cell_size <= CMP_EPSILON);
+ ERR_FAIL_COND(l_heights.size() != (width * depth));
+ setup(heights, width, depth, cell_size);
+}
+
+Variant HeightMapShapeBullet::get_data() const {
+ ERR_FAIL_V(Variant());
+}
+
+PhysicsServer::ShapeType HeightMapShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_HEIGHTMAP;
+}
+
+void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size) {
+ { // Copy
+ const int heights_size = p_heights.size();
+ heights.resize(heights_size);
+ PoolVector<real_t>::Read p_heights_r = p_heights.read();
+ PoolVector<real_t>::Write heights_w = heights.write();
+ for (int i = heights_size - 1; 0 <= i; --i) {
+ heights_w[i] = p_heights_r[i];
+ }
+ }
+ width = p_width;
+ depth = p_depth;
+ cell_size = p_cell_size;
+ notifyShapeChanged();
+}
+
+btCollisionShape *HeightMapShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_height_field(heights, width, depth, cell_size));
+}
+
+/* Ray shape */
+RayShapeBullet::RayShapeBullet()
+ : ShapeBullet(), length(1) {}
+
+void RayShapeBullet::set_data(const Variant &p_data) {
+ setup(p_data);
+}
+
+Variant RayShapeBullet::get_data() const {
+ return length;
+}
+
+PhysicsServer::ShapeType RayShapeBullet::get_type() const {
+ return PhysicsServer::SHAPE_RAY;
+}
+
+void RayShapeBullet::setup(real_t p_length) {
+ length = p_length;
+ notifyShapeChanged();
+}
+
+btCollisionShape *RayShapeBullet::create_bt_shape() {
+ return prepare(ShapeBullet::create_shape_ray(length));
+}
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
new file mode 100644
index 0000000000..0a56fa1709
--- /dev/null
+++ b/modules/bullet/shape_bullet.h
@@ -0,0 +1,225 @@
+/*************************************************************************/
+/* shape_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SHAPE_BULLET_H
+#define SHAPE_BULLET_H
+
+#include "LinearMath/btAlignedObjectArray.h"
+#include "LinearMath/btScalar.h"
+#include "LinearMath/btVector3.h"
+#include "core/variant.h"
+#include "geometry.h"
+#include "rid_bullet.h"
+#include "servers/physics_server.h"
+
+class ShapeBullet;
+class btCollisionShape;
+class ShapeOwnerBullet;
+class btBvhTriangleMeshShape;
+
+class ShapeBullet : public RIDBullet {
+
+ Map<ShapeOwnerBullet *, int> owners;
+
+protected:
+ /// return self
+ btCollisionShape *prepare(btCollisionShape *p_btShape) const;
+ void notifyShapeChanged();
+
+public:
+ ShapeBullet();
+ virtual ~ShapeBullet();
+
+ virtual btCollisionShape *create_bt_shape() = 0;
+
+ void add_owner(ShapeOwnerBullet *p_owner);
+ void remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody = false);
+ bool is_owner(ShapeOwnerBullet *p_owner) const;
+ const Map<ShapeOwnerBullet *, int> &get_owners() const;
+
+ /// Setup the shape
+ virtual void set_data(const Variant &p_data) = 0;
+ virtual Variant get_data() const = 0;
+
+ virtual PhysicsServer::ShapeType get_type() const = 0;
+
+public:
+ static class btEmptyShape *create_shape_empty();
+ static class btStaticPlaneShape *create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant);
+ static class btSphereShape *create_shape_sphere(btScalar radius);
+ static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents);
+ static class btCapsuleShapeZ *create_shape_capsule(btScalar radius, btScalar height);
+ /// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface();
+ static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
+ static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
+ static class btHeightfieldTerrainShape *create_shape_height_field(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size);
+ static class btRayShape *create_shape_ray(real_t p_length);
+};
+
+class PlaneShapeBullet : public ShapeBullet {
+
+ Plane plane;
+
+public:
+ PlaneShapeBullet();
+
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(const Plane &p_plane);
+};
+
+class SphereShapeBullet : public ShapeBullet {
+
+ real_t radius;
+
+public:
+ SphereShapeBullet();
+
+ _FORCE_INLINE_ real_t get_radius() { return radius; }
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(real_t p_radius);
+};
+
+class BoxShapeBullet : public ShapeBullet {
+
+ btVector3 half_extents;
+
+public:
+ BoxShapeBullet();
+
+ _FORCE_INLINE_ const btVector3 &get_half_extents() { return half_extents; }
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(const Vector3 &p_half_extents);
+};
+
+class CapsuleShapeBullet : public ShapeBullet {
+
+ real_t height;
+ real_t radius;
+
+public:
+ CapsuleShapeBullet();
+
+ _FORCE_INLINE_ real_t get_height() { return height; }
+ _FORCE_INLINE_ real_t get_radius() { return radius; }
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(real_t p_height, real_t p_radius);
+};
+
+class ConvexPolygonShapeBullet : public ShapeBullet {
+
+public:
+ btAlignedObjectArray<btVector3> vertices;
+
+ ConvexPolygonShapeBullet();
+
+ virtual void set_data(const Variant &p_data);
+ void get_vertices(Vector<Vector3> &out_vertices);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(const Vector<Vector3> &p_vertices);
+};
+
+class ConcavePolygonShapeBullet : public ShapeBullet {
+ class btBvhTriangleMeshShape *meshShape;
+
+public:
+ PoolVector<Vector3> faces;
+
+ ConcavePolygonShapeBullet();
+ virtual ~ConcavePolygonShapeBullet();
+
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(PoolVector<Vector3> p_faces);
+};
+
+class HeightMapShapeBullet : public ShapeBullet {
+
+public:
+ PoolVector<real_t> heights;
+ int width;
+ int depth;
+ real_t cell_size;
+
+ HeightMapShapeBullet();
+
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_cell_size);
+};
+
+class RayShapeBullet : public ShapeBullet {
+
+public:
+ real_t length;
+
+ RayShapeBullet();
+
+ virtual void set_data(const Variant &p_data);
+ virtual Variant get_data() const;
+ virtual PhysicsServer::ShapeType get_type() const;
+ virtual btCollisionShape *create_bt_shape();
+
+private:
+ void setup(real_t p_length);
+};
+#endif
diff --git a/modules/bullet/shape_owner_bullet.cpp b/modules/bullet/shape_owner_bullet.cpp
new file mode 100644
index 0000000000..04b2b01675
--- /dev/null
+++ b/modules/bullet/shape_owner_bullet.cpp
@@ -0,0 +1,32 @@
+/*************************************************************************/
+/* shape_owner_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "shape_owner_bullet.h"
diff --git a/modules/bullet/shape_owner_bullet.h b/modules/bullet/shape_owner_bullet.h
new file mode 100644
index 0000000000..d2f3d321c7
--- /dev/null
+++ b/modules/bullet/shape_owner_bullet.h
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* shape_owner_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SHAPE_OWNER_BULLET_H
+#define SHAPE_OWNER_BULLET_H
+
+#include "rid_bullet.h"
+
+class ShapeBullet;
+class btCollisionShape;
+class CollisionObjectBullet;
+
+/// Each clas that want to use Shapes must inherit this class
+/// E.G. BodyShape is a child of this
+class ShapeOwnerBullet {
+public:
+ /// This is used to set new shape or replace existing
+ //virtual void _internal_replaceShape(btCollisionShape *p_old_shape, btCollisionShape *p_new_shape) = 0;
+ virtual void on_shape_changed(const ShapeBullet *const p_shape) = 0;
+ virtual void on_shapes_changed() = 0;
+ virtual void remove_shape(class ShapeBullet *p_shape) = 0;
+ virtual ~ShapeOwnerBullet() {}
+};
+#endif
diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp
new file mode 100644
index 0000000000..2da65677f5
--- /dev/null
+++ b/modules/bullet/slider_joint_bullet.cpp
@@ -0,0 +1,385 @@
+/*************************************************************************/
+/* slider_joint_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "slider_joint_bullet.h"
+#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "rigid_body_bullet.h"
+
+SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB)
+ : JointBullet() {
+ btTransform btFrameA;
+ G_TO_B(frameInA, btFrameA);
+ if (rbB) {
+ btTransform btFrameB;
+ G_TO_B(frameInB, btFrameB);
+ sliderConstraint = bulletnew(btSliderConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB, true));
+
+ } else {
+ sliderConstraint = bulletnew(btSliderConstraint(*rbA->get_bt_rigid_body(), btFrameA, true));
+ }
+ setup(sliderConstraint);
+}
+
+const RigidBodyBullet *SliderJointBullet::getRigidBodyA() const {
+ return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyA().getUserPointer());
+}
+
+const RigidBodyBullet *SliderJointBullet::getRigidBodyB() const {
+ return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyB().getUserPointer());
+}
+
+const Transform SliderJointBullet::getCalculatedTransformA() const {
+ btTransform btTransform = sliderConstraint->getCalculatedTransformA();
+ Transform gTrans;
+ B_TO_G(btTransform, gTrans);
+ return gTrans;
+}
+
+const Transform SliderJointBullet::getCalculatedTransformB() const {
+ btTransform btTransform = sliderConstraint->getCalculatedTransformB();
+ Transform gTrans;
+ B_TO_G(btTransform, gTrans);
+ return gTrans;
+}
+
+const Transform SliderJointBullet::getFrameOffsetA() const {
+ btTransform btTransform = sliderConstraint->getFrameOffsetA();
+ Transform gTrans;
+ B_TO_G(btTransform, gTrans);
+ return gTrans;
+}
+
+const Transform SliderJointBullet::getFrameOffsetB() const {
+ btTransform btTransform = sliderConstraint->getFrameOffsetB();
+ Transform gTrans;
+ B_TO_G(btTransform, gTrans);
+ return gTrans;
+}
+
+Transform SliderJointBullet::getFrameOffsetA() {
+ btTransform btTransform = sliderConstraint->getFrameOffsetA();
+ Transform gTrans;
+ B_TO_G(btTransform, gTrans);
+ return gTrans;
+}
+
+Transform SliderJointBullet::getFrameOffsetB() {
+ btTransform btTransform = sliderConstraint->getFrameOffsetB();
+ Transform gTrans;
+ B_TO_G(btTransform, gTrans);
+ return gTrans;
+}
+
+real_t SliderJointBullet::getLowerLinLimit() const {
+ return sliderConstraint->getLowerLinLimit();
+}
+
+void SliderJointBullet::setLowerLinLimit(real_t lowerLimit) {
+ sliderConstraint->setLowerLinLimit(lowerLimit);
+}
+real_t SliderJointBullet::getUpperLinLimit() const {
+ return sliderConstraint->getUpperLinLimit();
+}
+
+void SliderJointBullet::setUpperLinLimit(real_t upperLimit) {
+ sliderConstraint->setUpperLinLimit(upperLimit);
+}
+
+real_t SliderJointBullet::getLowerAngLimit() const {
+ return sliderConstraint->getLowerAngLimit();
+}
+
+void SliderJointBullet::setLowerAngLimit(real_t lowerLimit) {
+ sliderConstraint->setLowerAngLimit(lowerLimit);
+}
+
+real_t SliderJointBullet::getUpperAngLimit() const {
+ return sliderConstraint->getUpperAngLimit();
+}
+
+void SliderJointBullet::setUpperAngLimit(real_t upperLimit) {
+ sliderConstraint->setUpperAngLimit(upperLimit);
+}
+
+real_t SliderJointBullet::getSoftnessDirLin() const {
+ return sliderConstraint->getSoftnessDirLin();
+}
+
+real_t SliderJointBullet::getRestitutionDirLin() const {
+ return sliderConstraint->getRestitutionDirLin();
+}
+
+real_t SliderJointBullet::getDampingDirLin() const {
+ return sliderConstraint->getDampingDirLin();
+}
+
+real_t SliderJointBullet::getSoftnessDirAng() const {
+ return sliderConstraint->getSoftnessDirAng();
+}
+
+real_t SliderJointBullet::getRestitutionDirAng() const {
+ return sliderConstraint->getRestitutionDirAng();
+}
+
+real_t SliderJointBullet::getDampingDirAng() const {
+ return sliderConstraint->getDampingDirAng();
+}
+
+real_t SliderJointBullet::getSoftnessLimLin() const {
+ return sliderConstraint->getSoftnessLimLin();
+}
+
+real_t SliderJointBullet::getRestitutionLimLin() const {
+ return sliderConstraint->getRestitutionLimLin();
+}
+
+real_t SliderJointBullet::getDampingLimLin() const {
+ return sliderConstraint->getDampingLimLin();
+}
+
+real_t SliderJointBullet::getSoftnessLimAng() const {
+ return sliderConstraint->getSoftnessLimAng();
+}
+
+real_t SliderJointBullet::getRestitutionLimAng() const {
+ return sliderConstraint->getRestitutionLimAng();
+}
+
+real_t SliderJointBullet::getDampingLimAng() const {
+ return sliderConstraint->getDampingLimAng();
+}
+
+real_t SliderJointBullet::getSoftnessOrthoLin() const {
+ return sliderConstraint->getSoftnessOrthoLin();
+}
+
+real_t SliderJointBullet::getRestitutionOrthoLin() const {
+ return sliderConstraint->getRestitutionOrthoLin();
+}
+
+real_t SliderJointBullet::getDampingOrthoLin() const {
+ return sliderConstraint->getDampingOrthoLin();
+}
+
+real_t SliderJointBullet::getSoftnessOrthoAng() const {
+ return sliderConstraint->getSoftnessOrthoAng();
+}
+
+real_t SliderJointBullet::getRestitutionOrthoAng() const {
+ return sliderConstraint->getRestitutionOrthoAng();
+}
+
+real_t SliderJointBullet::getDampingOrthoAng() const {
+ return sliderConstraint->getDampingOrthoAng();
+}
+
+void SliderJointBullet::setSoftnessDirLin(real_t softnessDirLin) {
+ sliderConstraint->setSoftnessDirLin(softnessDirLin);
+}
+
+void SliderJointBullet::setRestitutionDirLin(real_t restitutionDirLin) {
+ sliderConstraint->setRestitutionDirLin(restitutionDirLin);
+}
+
+void SliderJointBullet::setDampingDirLin(real_t dampingDirLin) {
+ sliderConstraint->setDampingDirLin(dampingDirLin);
+}
+
+void SliderJointBullet::setSoftnessDirAng(real_t softnessDirAng) {
+ sliderConstraint->setSoftnessDirAng(softnessDirAng);
+}
+
+void SliderJointBullet::setRestitutionDirAng(real_t restitutionDirAng) {
+ sliderConstraint->setRestitutionDirAng(restitutionDirAng);
+}
+
+void SliderJointBullet::setDampingDirAng(real_t dampingDirAng) {
+ sliderConstraint->setDampingDirAng(dampingDirAng);
+}
+
+void SliderJointBullet::setSoftnessLimLin(real_t softnessLimLin) {
+ sliderConstraint->setSoftnessLimLin(softnessLimLin);
+}
+
+void SliderJointBullet::setRestitutionLimLin(real_t restitutionLimLin) {
+ sliderConstraint->setRestitutionLimLin(restitutionLimLin);
+}
+
+void SliderJointBullet::setDampingLimLin(real_t dampingLimLin) {
+ sliderConstraint->setDampingLimLin(dampingLimLin);
+}
+
+void SliderJointBullet::setSoftnessLimAng(real_t softnessLimAng) {
+ sliderConstraint->setSoftnessLimAng(softnessLimAng);
+}
+
+void SliderJointBullet::setRestitutionLimAng(real_t restitutionLimAng) {
+ sliderConstraint->setRestitutionLimAng(restitutionLimAng);
+}
+
+void SliderJointBullet::setDampingLimAng(real_t dampingLimAng) {
+ sliderConstraint->setDampingLimAng(dampingLimAng);
+}
+
+void SliderJointBullet::setSoftnessOrthoLin(real_t softnessOrthoLin) {
+ sliderConstraint->setSoftnessOrthoLin(softnessOrthoLin);
+}
+
+void SliderJointBullet::setRestitutionOrthoLin(real_t restitutionOrthoLin) {
+ sliderConstraint->setRestitutionOrthoLin(restitutionOrthoLin);
+}
+
+void SliderJointBullet::setDampingOrthoLin(real_t dampingOrthoLin) {
+ sliderConstraint->setDampingOrthoLin(dampingOrthoLin);
+}
+
+void SliderJointBullet::setSoftnessOrthoAng(real_t softnessOrthoAng) {
+ sliderConstraint->setSoftnessOrthoAng(softnessOrthoAng);
+}
+
+void SliderJointBullet::setRestitutionOrthoAng(real_t restitutionOrthoAng) {
+ sliderConstraint->setRestitutionOrthoAng(restitutionOrthoAng);
+}
+
+void SliderJointBullet::setDampingOrthoAng(real_t dampingOrthoAng) {
+ sliderConstraint->setDampingOrthoAng(dampingOrthoAng);
+}
+
+void SliderJointBullet::setPoweredLinMotor(bool onOff) {
+ sliderConstraint->setPoweredLinMotor(onOff);
+}
+
+bool SliderJointBullet::getPoweredLinMotor() {
+ return sliderConstraint->getPoweredLinMotor();
+}
+
+void SliderJointBullet::setTargetLinMotorVelocity(real_t targetLinMotorVelocity) {
+ sliderConstraint->setTargetLinMotorVelocity(targetLinMotorVelocity);
+}
+
+real_t SliderJointBullet::getTargetLinMotorVelocity() {
+ return sliderConstraint->getTargetLinMotorVelocity();
+}
+
+void SliderJointBullet::setMaxLinMotorForce(real_t maxLinMotorForce) {
+ sliderConstraint->setMaxLinMotorForce(maxLinMotorForce);
+}
+
+real_t SliderJointBullet::getMaxLinMotorForce() {
+ return sliderConstraint->getMaxLinMotorForce();
+}
+
+void SliderJointBullet::setPoweredAngMotor(bool onOff) {
+ sliderConstraint->setPoweredAngMotor(onOff);
+}
+
+bool SliderJointBullet::getPoweredAngMotor() {
+ return sliderConstraint->getPoweredAngMotor();
+}
+
+void SliderJointBullet::setTargetAngMotorVelocity(real_t targetAngMotorVelocity) {
+ sliderConstraint->setTargetAngMotorVelocity(targetAngMotorVelocity);
+}
+
+real_t SliderJointBullet::getTargetAngMotorVelocity() {
+ return sliderConstraint->getTargetAngMotorVelocity();
+}
+
+void SliderJointBullet::setMaxAngMotorForce(real_t maxAngMotorForce) {
+ sliderConstraint->setMaxAngMotorForce(maxAngMotorForce);
+}
+
+real_t SliderJointBullet::getMaxAngMotorForce() {
+ return sliderConstraint->getMaxAngMotorForce();
+}
+
+real_t SliderJointBullet::getLinearPos() {
+ return sliderConstraint->getLinearPos();
+ ;
+}
+
+void SliderJointBullet::set_param(PhysicsServer::SliderJointParam p_param, real_t p_value) {
+ switch (p_param) {
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: setUpperLinLimit(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: setLowerLinLimit(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: setSoftnessLimLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: setRestitutionLimLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: setDampingLimLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: setSoftnessDirLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: setRestitutionDirLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: setDampingDirLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: setDampingOrthoLin(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: setUpperAngLimit(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: setLowerAngLimit(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: setSoftnessLimAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: setRestitutionLimAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: setDampingLimAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: setSoftnessDirAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: setRestitutionDirAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: setDampingDirAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: setSoftnessOrthoAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: setRestitutionOrthoAng(p_value); break;
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: setDampingOrthoAng(p_value); break;
+ }
+}
+
+real_t SliderJointBullet::get_param(PhysicsServer::SliderJointParam p_param) const {
+ switch (p_param) {
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return getUpperLinLimit();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER: return getLowerLinLimit();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS: return getSoftnessLimLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION: return getRestitutionLimLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING: return getDampingLimLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS: return getSoftnessDirLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION: return getRestitutionDirLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_MOTION_DAMPING: return getDampingDirLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoLin();
+ case PhysicsServer::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING: return getDampingOrthoLin();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER: return getUpperAngLimit();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER: return getLowerAngLimit();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS: return getSoftnessLimAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION: return getRestitutionLimAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING: return getDampingLimAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS: return getSoftnessDirAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION: return getRestitutionDirAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_MOTION_DAMPING: return getDampingDirAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS: return getSoftnessOrthoAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION: return getRestitutionOrthoAng();
+ case PhysicsServer::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING: return getDampingOrthoAng();
+ default:
+ return 0;
+ }
+}
diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h
new file mode 100644
index 0000000000..d50c376ea6
--- /dev/null
+++ b/modules/bullet/slider_joint_bullet.h
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* slider_joint_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SLIDER_JOINT_BULLET_H
+#define SLIDER_JOINT_BULLET_H
+
+#include "joint_bullet.h"
+
+class RigidBodyBullet;
+
+class SliderJointBullet : public JointBullet {
+ class btSliderConstraint *sliderConstraint;
+
+public:
+ /// Reference frame is A
+ SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB);
+
+ virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_SLIDER; }
+
+ const RigidBodyBullet *getRigidBodyA() const;
+ const RigidBodyBullet *getRigidBodyB() const;
+ const Transform getCalculatedTransformA() const;
+ const Transform getCalculatedTransformB() const;
+ const Transform getFrameOffsetA() const;
+ const Transform getFrameOffsetB() const;
+ Transform getFrameOffsetA();
+ Transform getFrameOffsetB();
+ real_t getLowerLinLimit() const;
+ void setLowerLinLimit(real_t lowerLimit);
+ real_t getUpperLinLimit() const;
+ void setUpperLinLimit(real_t upperLimit);
+ real_t getLowerAngLimit() const;
+ void setLowerAngLimit(real_t lowerLimit);
+ real_t getUpperAngLimit() const;
+ void setUpperAngLimit(real_t upperLimit);
+
+ real_t getSoftnessDirLin() const;
+ real_t getRestitutionDirLin() const;
+ real_t getDampingDirLin() const;
+ real_t getSoftnessDirAng() const;
+ real_t getRestitutionDirAng() const;
+ real_t getDampingDirAng() const;
+ real_t getSoftnessLimLin() const;
+ real_t getRestitutionLimLin() const;
+ real_t getDampingLimLin() const;
+ real_t getSoftnessLimAng() const;
+ real_t getRestitutionLimAng() const;
+ real_t getDampingLimAng() const;
+ real_t getSoftnessOrthoLin() const;
+ real_t getRestitutionOrthoLin() const;
+ real_t getDampingOrthoLin() const;
+ real_t getSoftnessOrthoAng() const;
+ real_t getRestitutionOrthoAng() const;
+ real_t getDampingOrthoAng() const;
+ void setSoftnessDirLin(real_t softnessDirLin);
+ void setRestitutionDirLin(real_t restitutionDirLin);
+ void setDampingDirLin(real_t dampingDirLin);
+ void setSoftnessDirAng(real_t softnessDirAng);
+ void setRestitutionDirAng(real_t restitutionDirAng);
+ void setDampingDirAng(real_t dampingDirAng);
+ void setSoftnessLimLin(real_t softnessLimLin);
+ void setRestitutionLimLin(real_t restitutionLimLin);
+ void setDampingLimLin(real_t dampingLimLin);
+ void setSoftnessLimAng(real_t softnessLimAng);
+ void setRestitutionLimAng(real_t restitutionLimAng);
+ void setDampingLimAng(real_t dampingLimAng);
+ void setSoftnessOrthoLin(real_t softnessOrthoLin);
+ void setRestitutionOrthoLin(real_t restitutionOrthoLin);
+ void setDampingOrthoLin(real_t dampingOrthoLin);
+ void setSoftnessOrthoAng(real_t softnessOrthoAng);
+ void setRestitutionOrthoAng(real_t restitutionOrthoAng);
+ void setDampingOrthoAng(real_t dampingOrthoAng);
+ void setPoweredLinMotor(bool onOff);
+ bool getPoweredLinMotor();
+ void setTargetLinMotorVelocity(real_t targetLinMotorVelocity);
+ real_t getTargetLinMotorVelocity();
+ void setMaxLinMotorForce(real_t maxLinMotorForce);
+ real_t getMaxLinMotorForce();
+ void setPoweredAngMotor(bool onOff);
+ bool getPoweredAngMotor();
+ void setTargetAngMotorVelocity(real_t targetAngMotorVelocity);
+ real_t getTargetAngMotorVelocity();
+ void setMaxAngMotorForce(real_t maxAngMotorForce);
+ real_t getMaxAngMotorForce();
+ real_t getLinearPos();
+
+ void set_param(PhysicsServer::SliderJointParam p_param, real_t p_value);
+ real_t get_param(PhysicsServer::SliderJointParam p_param) const;
+};
+#endif
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
new file mode 100644
index 0000000000..64ef7bfad2
--- /dev/null
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -0,0 +1,303 @@
+/*************************************************************************/
+/* soft_body_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "soft_body_bullet.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "space_bullet.h"
+
+#include "scene/3d/immediate_geometry.h"
+
+SoftBodyBullet::SoftBodyBullet()
+ : CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY), mass(1), simulation_precision(5), stiffness(0.5f), pressure_coefficient(50), damping_coefficient(0.005), drag_coefficient(0.005), bt_soft_body(NULL), soft_shape_type(SOFT_SHAPETYPE_NONE), isScratched(false), soft_body_shape_data(NULL) {
+
+ test_geometry = memnew(ImmediateGeometry);
+
+ red_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+ red_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ red_mat->set_line_width(20.0);
+ red_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ red_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ red_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ red_mat->set_albedo(Color(1, 0, 0, 1));
+ test_geometry->set_material_override(red_mat);
+
+ test_is_in_scene = false;
+}
+
+SoftBodyBullet::~SoftBodyBullet() {
+ bulletdelete(soft_body_shape_data);
+}
+
+void SoftBodyBullet::reload_body() {
+ if (space) {
+ space->remove_soft_body(this);
+ space->add_soft_body(this);
+ }
+}
+
+void SoftBodyBullet::set_space(SpaceBullet *p_space) {
+ if (space) {
+ isScratched = false;
+
+ // Remove this object from the physics world
+ space->remove_soft_body(this);
+ }
+
+ space = p_space;
+
+ if (space) {
+ space->add_soft_body(this);
+ }
+
+ reload_soft_body();
+}
+
+void SoftBodyBullet::dispatch_callbacks() {
+ if (!bt_soft_body) {
+ return;
+ }
+
+ if (!test_is_in_scene) {
+ test_is_in_scene = true;
+ SceneTree::get_singleton()->get_current_scene()->add_child(test_geometry);
+ }
+
+ test_geometry->clear();
+ test_geometry->begin(Mesh::PRIMITIVE_LINES, NULL);
+ bool first = true;
+ Vector3 pos;
+ for (int i = 0; i < bt_soft_body->m_nodes.size(); ++i) {
+ const btSoftBody::Node &n = bt_soft_body->m_nodes[i];
+ B_TO_G(n.m_x, pos);
+ test_geometry->add_vertex(pos);
+ if (!first) {
+ test_geometry->add_vertex(pos);
+ } else {
+ first = false;
+ }
+ }
+ test_geometry->end();
+}
+
+void SoftBodyBullet::on_collision_filters_change() {
+}
+
+void SoftBodyBullet::on_collision_checker_start() {
+}
+
+void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {
+}
+
+void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {
+}
+
+void SoftBodyBullet::set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) {
+
+ TrimeshSoftShapeData *shape_data = bulletnew(TrimeshSoftShapeData);
+ shape_data->m_triangles_indices = p_indices;
+ shape_data->m_vertices = p_vertices;
+ shape_data->m_triangles_num = p_triangles_num;
+
+ set_body_shape_data(shape_data, SOFT_SHAPE_TYPE_TRIMESH);
+ reload_soft_body();
+}
+
+void SoftBodyBullet::set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type) {
+ bulletdelete(soft_body_shape_data);
+ soft_body_shape_data = p_soft_shape_data;
+ soft_shape_type = p_type;
+}
+
+void SoftBodyBullet::set_transform(const Transform &p_transform) {
+ transform = p_transform;
+ if (bt_soft_body) {
+ // TODO the softbody set new transform considering the current transform as center of world
+ // like if it's local transform, so I must fix this by setting nwe transform considering the old
+ btTransform bt_trans;
+ G_TO_B(transform, bt_trans);
+ //bt_soft_body->transform(bt_trans);
+ }
+}
+
+const Transform &SoftBodyBullet::get_transform() const {
+ return transform;
+}
+
+void SoftBodyBullet::get_first_node_origin(btVector3 &p_out_origin) const {
+ if (bt_soft_body && bt_soft_body->m_nodes.size()) {
+ p_out_origin = bt_soft_body->m_nodes[0].m_x;
+ } else {
+ p_out_origin.setZero();
+ }
+}
+
+void SoftBodyBullet::set_activation_state(bool p_active) {
+ if (p_active) {
+ bt_soft_body->setActivationState(ACTIVE_TAG);
+ } else {
+ bt_soft_body->setActivationState(WANTS_DEACTIVATION);
+ }
+}
+
+void SoftBodyBullet::set_mass(real_t p_val) {
+ if (0 >= p_val) {
+ p_val = 1;
+ }
+ mass = p_val;
+ if (bt_soft_body) {
+ bt_soft_body->setTotalMass(mass);
+ }
+}
+
+void SoftBodyBullet::set_stiffness(real_t p_val) {
+ stiffness = p_val;
+ if (bt_soft_body) {
+ mat0->m_kAST = stiffness;
+ mat0->m_kLST = stiffness;
+ mat0->m_kVST = stiffness;
+ }
+}
+
+void SoftBodyBullet::set_simulation_precision(int p_val) {
+ simulation_precision = p_val;
+ if (bt_soft_body) {
+ bt_soft_body->m_cfg.piterations = simulation_precision;
+ }
+}
+
+void SoftBodyBullet::set_pressure_coefficient(real_t p_val) {
+ pressure_coefficient = p_val;
+ if (bt_soft_body) {
+ bt_soft_body->m_cfg.kPR = pressure_coefficient;
+ }
+}
+
+void SoftBodyBullet::set_damping_coefficient(real_t p_val) {
+ damping_coefficient = p_val;
+ if (bt_soft_body) {
+ bt_soft_body->m_cfg.kDP = damping_coefficient;
+ }
+}
+
+void SoftBodyBullet::set_drag_coefficient(real_t p_val) {
+ drag_coefficient = p_val;
+ if (bt_soft_body) {
+ bt_soft_body->m_cfg.kDG = drag_coefficient;
+ }
+}
+
+void SoftBodyBullet::reload_soft_body() {
+
+ destroy_soft_body();
+ create_soft_body();
+
+ if (bt_soft_body) {
+
+ // TODO the softbody set new transform considering the current transform as center of world
+ // like if it's local transform, so I must fix this by setting nwe transform considering the old
+ btTransform bt_trans;
+ G_TO_B(transform, bt_trans);
+ bt_soft_body->transform(bt_trans);
+
+ bt_soft_body->generateBendingConstraints(2, mat0);
+ mat0->m_kAST = stiffness;
+ mat0->m_kLST = stiffness;
+ mat0->m_kVST = stiffness;
+
+ bt_soft_body->m_cfg.piterations = simulation_precision;
+ bt_soft_body->m_cfg.kDP = damping_coefficient;
+ bt_soft_body->m_cfg.kDG = drag_coefficient;
+ bt_soft_body->m_cfg.kPR = pressure_coefficient;
+ bt_soft_body->setTotalMass(mass);
+ }
+ if (space) {
+ // TODO remove this please
+ space->add_soft_body(this);
+ }
+}
+
+void SoftBodyBullet::create_soft_body() {
+ if (!space || !soft_body_shape_data) {
+ return;
+ }
+ ERR_FAIL_COND(!space->is_using_soft_world());
+ switch (soft_shape_type) {
+ case SOFT_SHAPE_TYPE_TRIMESH: {
+ TrimeshSoftShapeData *trimesh_data = static_cast<TrimeshSoftShapeData *>(soft_body_shape_data);
+
+ Vector<int> indices;
+ Vector<btScalar> vertices;
+
+ int i;
+ const int indices_size = trimesh_data->m_triangles_indices.size();
+ const int vertices_size = trimesh_data->m_vertices.size();
+ indices.resize(indices_size);
+ vertices.resize(vertices_size * 3);
+
+ PoolVector<int>::Read i_r = trimesh_data->m_triangles_indices.read();
+ for (i = 0; i < indices_size; ++i) {
+ indices[i] = i_r[i];
+ }
+ i_r = PoolVector<int>::Read();
+
+ PoolVector<Vector3>::Read f_r = trimesh_data->m_vertices.read();
+ for (int j = i = 0; i < vertices_size; ++i, j += 3) {
+ vertices[j + 0] = f_r[i][0];
+ vertices[j + 1] = f_r[i][1];
+ vertices[j + 2] = f_r[i][2];
+ }
+ f_r = PoolVector<Vector3>::Read();
+
+ bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(*space->get_soft_body_world_info(), vertices.ptr(), indices.ptr(), trimesh_data->m_triangles_num);
+ } break;
+ default:
+ ERR_PRINT("Shape type not supported");
+ return;
+ }
+
+ setupBulletCollisionObject(bt_soft_body);
+ bt_soft_body->getCollisionShape()->setMargin(0.001f);
+ bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT)));
+ mat0 = bt_soft_body->appendMaterial();
+}
+
+void SoftBodyBullet::destroy_soft_body() {
+ if (space) {
+ /// This step is required to assert that the body is not into the world during deletion
+ /// This step is required since to change the body shape the body must be re-created.
+ /// Here is handled the case when the body is assigned into a world and the body
+ /// shape is changed.
+ space->remove_soft_body(this);
+ }
+ destroyBulletCollisionObject();
+ bt_soft_body = NULL;
+}
diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h
new file mode 100644
index 0000000000..9ee7cd76d3
--- /dev/null
+++ b/modules/bullet/soft_body_bullet.h
@@ -0,0 +1,136 @@
+/*************************************************************************/
+/* soft_body_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SOFT_BODY_BULLET_H
+#define SOFT_BODY_BULLET_H
+
+#ifdef None
+/// This is required to remove the macro None defined by x11 compiler because this word "None" is used internally by Bullet
+#undef None
+#define x11_None 0L
+#endif
+
+#include "BulletSoftBody/btSoftBodyHelpers.h"
+#include "collision_object_bullet.h"
+
+#ifdef x11_None
+/// This is required to re add the macro None defined by x11 compiler
+#undef x11_None
+#define None 0L
+#endif
+
+#include "scene/resources/material.h" // TODO remove thsi please
+
+struct SoftShapeData {};
+struct TrimeshSoftShapeData : public SoftShapeData {
+ PoolVector<int> m_triangles_indices;
+ PoolVector<Vector3> m_vertices;
+ int m_triangles_num;
+};
+
+class SoftBodyBullet : public CollisionObjectBullet {
+public:
+ enum SoftShapeType {
+ SOFT_SHAPETYPE_NONE = 0,
+ SOFT_SHAPE_TYPE_TRIMESH
+ };
+
+private:
+ btSoftBody *bt_soft_body;
+ btSoftBody::Material *mat0; // This is just a copy of pointer managed by btSoftBody
+ SoftShapeType soft_shape_type;
+ bool isScratched;
+
+ SoftShapeData *soft_body_shape_data;
+
+ Transform transform;
+ int simulation_precision;
+ real_t mass;
+ real_t stiffness; // [0,1]
+ real_t pressure_coefficient; // [-inf,+inf]
+ real_t damping_coefficient; // [0,1]
+ real_t drag_coefficient; // [0,1]
+
+ class ImmediateGeometry *test_geometry; // TODO remove this please
+ Ref<SpatialMaterial> red_mat; // TODO remove this please
+ bool test_is_in_scene; // TODO remove this please
+
+public:
+ SoftBodyBullet();
+ ~SoftBodyBullet();
+
+ virtual void reload_body();
+ virtual void set_space(SpaceBullet *p_space);
+
+ virtual void dispatch_callbacks();
+ virtual void on_collision_filters_change();
+ virtual void on_collision_checker_start();
+ virtual void on_enter_area(AreaBullet *p_area);
+ virtual void on_exit_area(AreaBullet *p_area);
+
+ _FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; }
+
+ void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num);
+ void set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type);
+
+ void set_transform(const Transform &p_transform);
+ /// This function doesn't return the exact COM transform.
+ /// It returns the origin only of first node (vertice) of current soft body
+ /// ---
+ /// The soft body doesn't have a fixed center of mass, but is a group of nodes (vertices)
+ /// that each has its own position in the world.
+ /// For this reason return the correct COM is not so simple and must be calculate
+ /// Check this to improve this function http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=8803
+ const Transform &get_transform() const;
+ void get_first_node_origin(btVector3 &p_out_origin) const;
+
+ void set_activation_state(bool p_active);
+
+ void set_mass(real_t p_val);
+ _FORCE_INLINE_ real_t get_mass() const { return mass; }
+ void set_stiffness(real_t p_val);
+ _FORCE_INLINE_ real_t get_stiffness() const { return stiffness; }
+ void set_simulation_precision(int p_val);
+ _FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; }
+ void set_pressure_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; }
+ void set_damping_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; }
+ void set_drag_coefficient(real_t p_val);
+ _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; }
+
+private:
+ void reload_soft_body();
+ void create_soft_body();
+ void destroy_soft_body();
+};
+
+#endif // SOFT_BODY_BULLET_H
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
new file mode 100644
index 0000000000..af7f511fab
--- /dev/null
+++ b/modules/bullet/space_bullet.cpp
@@ -0,0 +1,1163 @@
+/*************************************************************************/
+/* space_bullet.cpp */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "space_bullet.h"
+#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
+#include "BulletCollision/CollisionDispatch/btGhostObject.h"
+#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
+#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h"
+#include "BulletCollision/NarrowPhaseCollision/btPointCollector.h"
+#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h"
+#include "BulletSoftBody/btSoftRigidDynamicsWorld.h"
+#include "btBulletDynamicsCommon.h"
+#include "bullet_physics_server.h"
+#include "bullet_types_converter.h"
+#include "bullet_utilities.h"
+#include "constraint_bullet.h"
+#include "godot_collision_configuration.h"
+#include "godot_collision_dispatcher.h"
+#include "rigid_body_bullet.h"
+#include "servers/physics_server.h"
+#include "soft_body_bullet.h"
+#include "ustring.h"
+#include <assert.h>
+
+// test only
+//#include "scene/3d/immediate_geometry.h"
+
+BulletPhysicsDirectSpaceState::BulletPhysicsDirectSpaceState(SpaceBullet *p_space)
+ : PhysicsDirectSpaceState(), space(p_space) {}
+
+int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) {
+
+ if (p_result_max <= 0)
+ return 0;
+
+ btVector3 bt_point;
+ G_TO_B(p_point, bt_point);
+
+ btSphereShape sphere_point(0.f);
+ btCollisionObject collision_object_point;
+ collision_object_point.setCollisionShape(&sphere_point);
+ collision_object_point.setWorldTransform(btTransform(btQuaternion::getIdentity(), bt_point));
+
+ // Setup query
+ GodotAllContactResultCallback btResult(&collision_object_point, r_results, p_result_max, &p_exclude);
+ btResult.m_collisionFilterGroup = p_collision_layer;
+ btResult.m_collisionFilterMask = p_object_type_mask;
+ space->dynamicsWorld->contactTest(&collision_object_point, btResult);
+
+ // The results is already populated by GodotAllConvexResultCallback
+ return btResult.m_count;
+}
+
+bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, bool p_pick_ray) {
+
+ btVector3 btVec_from;
+ btVector3 btVec_to;
+
+ G_TO_B(p_from, btVec_from);
+ G_TO_B(p_to, btVec_to);
+
+ // setup query
+ GodotClosestRayResultCallback btResult(btVec_from, btVec_to, &p_exclude);
+ btResult.m_collisionFilterGroup = p_collision_layer;
+ btResult.m_collisionFilterMask = p_object_type_mask;
+ btResult.m_pickRay = p_pick_ray;
+
+ space->dynamicsWorld->rayTest(btVec_from, btVec_to, btResult);
+ if (btResult.hasHit()) {
+ B_TO_G(btResult.m_hitPointWorld, r_result.position);
+ B_TO_G(btResult.m_hitNormalWorld.normalize(), r_result.normal);
+ CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btResult.m_collisionObject->getUserPointer());
+ if (gObj) {
+ r_result.shape = 0;
+ r_result.rid = gObj->get_self();
+ r_result.collider_id = gObj->get_instance_id();
+ r_result.collider = 0 == r_result.collider_id ? NULL : ObjectDB::get_instance(r_result.collider_id);
+ } else {
+ WARN_PRINTS("The raycast performed has hit a collision object that is not part of Godot scene, please check it.");
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *p_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask) {
+ if (p_result_max <= 0)
+ return 0;
+
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape);
+
+ btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape());
+ if (!btConvex) {
+ bulletdelete(btConvex);
+ ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
+ return 0;
+ }
+
+ btVector3 scale_with_margin;
+ G_TO_B(p_xform.basis.get_scale(), scale_with_margin);
+ btConvex->setLocalScaling(scale_with_margin);
+
+ btTransform bt_xform;
+ G_TO_B(p_xform, bt_xform);
+
+ btCollisionObject collision_object;
+ collision_object.setCollisionShape(btConvex);
+ collision_object.setWorldTransform(bt_xform);
+
+ GodotAllContactResultCallback btQuery(&collision_object, p_results, p_result_max, &p_exclude);
+ btQuery.m_collisionFilterGroup = p_collision_layer;
+ btQuery.m_collisionFilterMask = p_object_type_mask;
+ btQuery.m_closestDistanceThreshold = p_margin;
+ space->dynamicsWorld->contactTest(&collision_object, btQuery);
+
+ bulletdelete(btConvex);
+
+ return btQuery.m_count;
+}
+
+bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_layer, uint32_t p_object_type_mask, ShapeRestInfo *r_info) {
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape);
+
+ btConvexShape *bt_convex_shape = dynamic_cast<btConvexShape *>(shape->create_bt_shape());
+ if (!bt_convex_shape) {
+ bulletdelete(bt_convex_shape);
+ ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
+ return 0;
+ }
+
+ btVector3 bt_motion;
+ G_TO_B(p_motion, bt_motion);
+
+ btVector3 scale_with_margin;
+ G_TO_B(p_xform.basis.get_scale() + Vector3(p_margin, p_margin, p_margin), scale_with_margin);
+ bt_convex_shape->setLocalScaling(scale_with_margin);
+
+ btTransform bt_xform_from;
+ G_TO_B(p_xform, bt_xform_from);
+
+ btTransform bt_xform_to(bt_xform_from);
+ bt_xform_to.getOrigin() += bt_motion;
+
+ GodotClosestConvexResultCallback btResult(bt_xform_from.getOrigin(), bt_xform_to.getOrigin(), &p_exclude);
+ btResult.m_collisionFilterGroup = p_collision_layer;
+ btResult.m_collisionFilterMask = p_object_type_mask;
+
+ space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult);
+
+ if (btResult.hasHit()) {
+ if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) {
+ B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity);
+ }
+ CollisionObjectBullet *collision_object = static_cast<CollisionObjectBullet *>(btResult.m_hitCollisionObject->getUserPointer());
+ p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction;
+ B_TO_G(btResult.m_hitPointWorld, r_info->point);
+ B_TO_G(btResult.m_hitNormalWorld, r_info->normal);
+ r_info->rid = collision_object->get_self();
+ r_info->collider_id = collision_object->get_instance_id();
+ r_info->shape = btResult.m_shapePart;
+ }
+
+ bulletdelete(bt_convex_shape);
+ return btResult.hasHit();
+}
+
+/// 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_layer, uint32_t p_object_type_mask) {
+ if (p_result_max <= 0)
+ return 0;
+
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape);
+
+ btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape());
+ if (!btConvex) {
+ bulletdelete(btConvex);
+ ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
+ return 0;
+ }
+
+ btVector3 scale_with_margin;
+ G_TO_B(p_shape_xform.basis.get_scale(), scale_with_margin);
+ btConvex->setLocalScaling(scale_with_margin);
+
+ btTransform bt_xform;
+ G_TO_B(p_shape_xform, bt_xform);
+
+ btCollisionObject collision_object;
+ collision_object.setCollisionShape(btConvex);
+ collision_object.setWorldTransform(bt_xform);
+
+ GodotContactPairContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude);
+ btQuery.m_collisionFilterGroup = p_collision_layer;
+ btQuery.m_collisionFilterMask = p_object_type_mask;
+ btQuery.m_closestDistanceThreshold = p_margin;
+ space->dynamicsWorld->contactTest(&collision_object, btQuery);
+
+ r_result_count = btQuery.m_count;
+ bulletdelete(btConvex);
+
+ 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_layer, uint32_t p_object_type_mask) {
+
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape);
+
+ btConvexShape *btConvex = dynamic_cast<btConvexShape *>(shape->create_bt_shape());
+ if (!btConvex) {
+ bulletdelete(btConvex);
+ ERR_PRINTS("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type()));
+ return 0;
+ }
+
+ btVector3 scale_with_margin;
+ G_TO_B(p_shape_xform.basis.get_scale() + Vector3(p_margin, p_margin, p_margin), scale_with_margin);
+ btConvex->setLocalScaling(scale_with_margin);
+
+ btTransform bt_xform;
+ G_TO_B(p_shape_xform, bt_xform);
+
+ btCollisionObject collision_object;
+ collision_object.setCollisionShape(btConvex);
+ collision_object.setWorldTransform(bt_xform);
+
+ GodotRestInfoContactResultCallback btQuery(&collision_object, r_info, &p_exclude);
+ btQuery.m_collisionFilterGroup = p_collision_layer;
+ btQuery.m_collisionFilterMask = p_object_type_mask;
+ btQuery.m_closestDistanceThreshold = p_margin;
+ space->dynamicsWorld->contactTest(&collision_object, btQuery);
+
+ bulletdelete(btConvex);
+
+ if (btQuery.m_collided) {
+ if (btCollisionObject::CO_RIGID_BODY == btQuery.m_rest_info_collision_object->getInternalType()) {
+ B_TO_G(static_cast<const btRigidBody *>(btQuery.m_rest_info_collision_object)->getVelocityInLocalPoint(btQuery.m_rest_info_bt_point), r_info->linear_velocity);
+ }
+ B_TO_G(btQuery.m_rest_info_bt_point, r_info->point);
+ }
+
+ return btQuery.m_collided;
+}
+
+Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const {
+
+ RigidCollisionObjectBullet *rigid_object = space->get_physics_server()->get_rigid_collisin_object(p_object);
+ ERR_FAIL_COND_V(!rigid_object, Vector3());
+
+ btVector3 out_closest_point(0, 0, 0);
+ btScalar out_distance = 1e20;
+
+ btVector3 bt_point;
+ G_TO_B(p_point, bt_point);
+
+ btGjkEpaPenetrationDepthSolver gjk_epa_pen_solver;
+ btVoronoiSimplexSolver gjk_simplex_solver;
+ gjk_simplex_solver.setEqualVertexThreshold(0.);
+
+ btSphereShape point_shape(0.);
+
+ btCollisionShape *shape;
+ btConvexShape *convex_shape;
+ btTransform child_transform;
+ btTransform body_transform(rigid_object->get_bt_collision_object()->getWorldTransform());
+
+ btGjkPairDetector::ClosestPointInput input;
+ input.m_transformA.getBasis().setIdentity();
+ input.m_transformA.setOrigin(bt_point);
+
+ bool shapes_found = false;
+
+ btCompoundShape *compound = rigid_object->get_compound_shape();
+ for (int i = compound->getNumChildShapes() - 1; 0 <= i; --i) {
+ shape = compound->getChildShape(i);
+ if (shape->isConvex()) {
+ child_transform = compound->getChildTransform(i);
+ convex_shape = static_cast<btConvexShape *>(shape);
+
+ input.m_transformB = body_transform * child_transform;
+
+ btPointCollector result;
+ btGjkPairDetector gjk_pair_detector(&point_shape, convex_shape, &gjk_simplex_solver, &gjk_epa_pen_solver);
+ gjk_pair_detector.getClosestPoints(input, result, 0);
+
+ if (out_distance > result.m_distance) {
+ out_distance = result.m_distance;
+ out_closest_point = result.m_pointInWorld;
+ }
+ }
+ shapes_found = true;
+ }
+
+ if (shapes_found) {
+
+ Vector3 out;
+ B_TO_G(out_closest_point, out);
+ return out;
+ } else {
+
+ // no shapes found, use distance to origin.
+ return rigid_object->get_transform().get_origin();
+ }
+}
+
+SpaceBullet::SpaceBullet(bool p_create_soft_world)
+ : broadphase(NULL),
+ dispatcher(NULL),
+ solver(NULL),
+ collisionConfiguration(NULL),
+ dynamicsWorld(NULL),
+ soft_body_world_info(NULL),
+ ghostPairCallback(NULL),
+ godotFilterCallback(NULL),
+ gravityDirection(0, -1, 0),
+ gravityMagnitude(10),
+ contactDebugCount(0) {
+
+ create_empty_world(p_create_soft_world);
+ direct_access = memnew(BulletPhysicsDirectSpaceState(this));
+}
+
+SpaceBullet::~SpaceBullet() {
+ memdelete(direct_access);
+ destroy_world();
+}
+
+void SpaceBullet::flush_queries() {
+ const btCollisionObjectArray &colObjArray = dynamicsWorld->getCollisionObjectArray();
+ for (int i = colObjArray.size() - 1; 0 <= i; --i) {
+ static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->dispatch_callbacks();
+ }
+}
+
+void SpaceBullet::step(real_t p_delta_time) {
+ dynamicsWorld->stepSimulation(p_delta_time, 0, 0);
+}
+
+void SpaceBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value) {
+ assert(dynamicsWorld);
+
+ switch (p_param) {
+ case PhysicsServer::AREA_PARAM_GRAVITY:
+ gravityMagnitude = p_value;
+ update_gravity();
+ break;
+ case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ gravityDirection = p_value;
+ update_gravity();
+ break;
+ case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
+ case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ break; // No damp
+ case PhysicsServer::AREA_PARAM_PRIORITY:
+ // Priority is always 0, the lower
+ break;
+ case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
+ case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ break;
+ default:
+ WARN_PRINTS("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it.");
+ break;
+ }
+}
+
+Variant SpaceBullet::get_param(PhysicsServer::AreaParameter p_param) {
+ switch (p_param) {
+ case PhysicsServer::AREA_PARAM_GRAVITY:
+ return gravityMagnitude;
+ case PhysicsServer::AREA_PARAM_GRAVITY_VECTOR:
+ return gravityDirection;
+ case PhysicsServer::AREA_PARAM_LINEAR_DAMP:
+ case PhysicsServer::AREA_PARAM_ANGULAR_DAMP:
+ return 0; // No damp
+ case PhysicsServer::AREA_PARAM_PRIORITY:
+ return 0; // Priority is always 0, the lower
+ case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT:
+ return false;
+ case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE:
+ return 0;
+ case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
+ return 0;
+ default:
+ WARN_PRINTS("This get parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it.");
+ return Variant();
+ }
+}
+
+void SpaceBullet::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) {
+ switch (p_param) {
+ case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
+ case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION:
+ case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
+ case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP:
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
+ case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
+ default:
+ WARN_PRINTS("This set parameter (" + itos(p_param) + ") is ignored, the SpaceBullet doesn't support it.");
+ break;
+ }
+}
+
+real_t SpaceBullet::get_param(PhysicsServer::SpaceParameter p_param) {
+ switch (p_param) {
+ case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS:
+ case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION:
+ case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION:
+ case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD:
+ case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP:
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO:
+ case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS:
+ default:
+ WARN_PRINTS("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned.");
+ return 0.f;
+ }
+}
+
+void SpaceBullet::add_area(AreaBullet *p_area) {
+ areas.push_back(p_area);
+ dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask());
+}
+
+void SpaceBullet::remove_area(AreaBullet *p_area) {
+ areas.erase(p_area);
+ dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost());
+}
+
+void SpaceBullet::reload_collision_filters(AreaBullet *p_area) {
+ // This is necessary to change collision filter
+ dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost());
+ dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask());
+}
+
+void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) {
+ if (p_body->is_static()) {
+ dynamicsWorld->addCollisionObject(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask());
+ } else {
+ dynamicsWorld->addRigidBody(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask());
+ }
+}
+
+void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) {
+ if (p_body->is_static()) {
+ dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body());
+ } else {
+ dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body());
+ }
+}
+
+void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) {
+ // This is necessary to change collision filter
+ remove_rigid_body(p_body);
+ add_rigid_body(p_body);
+}
+
+void SpaceBullet::add_soft_body(SoftBodyBullet *p_body) {
+ if (is_using_soft_world()) {
+ if (p_body->get_bt_soft_body()) {
+ static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->addSoftBody(p_body->get_bt_soft_body(), p_body->get_collision_layer(), p_body->get_collision_mask());
+ }
+ } else {
+ ERR_PRINT("This soft body can't be added to non soft world");
+ }
+}
+
+void SpaceBullet::remove_soft_body(SoftBodyBullet *p_body) {
+ if (is_using_soft_world()) {
+ if (p_body->get_bt_soft_body()) {
+ static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->removeSoftBody(p_body->get_bt_soft_body());
+ }
+ }
+}
+
+void SpaceBullet::reload_collision_filters(SoftBodyBullet *p_body) {
+ // This is necessary to change collision filter
+ remove_soft_body(p_body);
+ add_soft_body(p_body);
+}
+
+void SpaceBullet::add_constraint(ConstraintBullet *p_constraint, bool disableCollisionsBetweenLinkedBodies) {
+ p_constraint->set_space(this);
+ dynamicsWorld->addConstraint(p_constraint->get_bt_constraint(), disableCollisionsBetweenLinkedBodies);
+}
+
+void SpaceBullet::remove_constraint(ConstraintBullet *p_constraint) {
+ dynamicsWorld->removeConstraint(p_constraint->get_bt_constraint());
+}
+
+int SpaceBullet::get_num_collision_objects() const {
+ return dynamicsWorld->getNumCollisionObjects();
+}
+
+void SpaceBullet::remove_all_collision_objects() {
+ for (int i = dynamicsWorld->getNumCollisionObjects() - 1; 0 <= i; --i) {
+ btCollisionObject *btObj = dynamicsWorld->getCollisionObjectArray()[i];
+ CollisionObjectBullet *colObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+ colObj->set_space(NULL);
+ }
+}
+
+void onBulletPreTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) {
+ static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo())->flush_queries();
+}
+
+void onBulletTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) {
+
+ // Notify all Collision objects the collision checker is started
+ const btCollisionObjectArray &colObjArray = p_dynamicsWorld->getCollisionObjectArray();
+ for (int i = colObjArray.size() - 1; 0 <= i; --i) {
+ CollisionObjectBullet *colObj = static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer());
+ assert(NULL != colObj);
+ colObj->on_collision_checker_start();
+ }
+
+ SpaceBullet *sb = static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo());
+ sb->check_ghost_overlaps();
+ sb->check_body_collision();
+}
+
+BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() {
+ return direct_access;
+}
+
+btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) {
+ return MAX(body0->getRestitution(), body1->getRestitution());
+}
+
+void SpaceBullet::create_empty_world(bool p_create_soft_world) {
+ assert(NULL == broadphase);
+ assert(NULL == dispatcher);
+ assert(NULL == solver);
+ assert(NULL == collisionConfiguration);
+ assert(NULL == dynamicsWorld);
+ assert(NULL == ghostPairCallback);
+ assert(NULL == godotFilterCallback);
+
+ void *world_mem;
+ if (p_create_soft_world) {
+ world_mem = malloc(sizeof(btSoftRigidDynamicsWorld));
+ } else {
+ world_mem = malloc(sizeof(btDiscreteDynamicsWorld));
+ }
+
+ if (p_create_soft_world) {
+ collisionConfiguration = bulletnew(btSoftBodyRigidBodyCollisionConfiguration);
+ } else {
+ collisionConfiguration = bulletnew(GodotCollisionConfiguration(static_cast<btDiscreteDynamicsWorld *>(world_mem)));
+ }
+
+ dispatcher = bulletnew(GodotCollisionDispatcher(collisionConfiguration));
+ broadphase = bulletnew(btDbvtBroadphase);
+ solver = bulletnew(btSequentialImpulseConstraintSolver);
+
+ if (p_create_soft_world) {
+ dynamicsWorld = new (world_mem) btSoftRigidDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
+ soft_body_world_info = bulletnew(btSoftBodyWorldInfo);
+ } else {
+ dynamicsWorld = new (world_mem) btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
+ }
+
+ ghostPairCallback = bulletnew(btGhostPairCallback);
+ godotFilterCallback = bulletnew(GodotFilterCallback);
+ gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution;
+
+ dynamicsWorld->setWorldUserInfo(this);
+
+ dynamicsWorld->setInternalTickCallback(onBulletPreTickCallback, this, true);
+ dynamicsWorld->setInternalTickCallback(onBulletTickCallback, this, false);
+ dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(ghostPairCallback); // Setup ghost check
+ dynamicsWorld->getPairCache()->setOverlapFilterCallback(godotFilterCallback);
+
+ if (soft_body_world_info) {
+ soft_body_world_info->m_broadphase = broadphase;
+ soft_body_world_info->m_dispatcher = dispatcher;
+ soft_body_world_info->m_sparsesdf.Initialize();
+ }
+
+ update_gravity();
+}
+
+void SpaceBullet::destroy_world() {
+ assert(NULL != broadphase);
+ assert(NULL != dispatcher);
+ assert(NULL != solver);
+ assert(NULL != collisionConfiguration);
+ assert(NULL != dynamicsWorld);
+ assert(NULL != ghostPairCallback);
+ assert(NULL != godotFilterCallback);
+
+ /// The world elements (like: Collision Objects, Constraints, Shapes) are managed by godot
+
+ dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(NULL);
+ dynamicsWorld->getPairCache()->setOverlapFilterCallback(NULL);
+
+ bulletdelete(ghostPairCallback);
+ bulletdelete(godotFilterCallback);
+
+ // Deallocate world
+ dynamicsWorld->~btDiscreteDynamicsWorld();
+ free(dynamicsWorld);
+ dynamicsWorld = NULL;
+
+ bulletdelete(solver);
+ bulletdelete(broadphase);
+ bulletdelete(dispatcher);
+ bulletdelete(collisionConfiguration);
+ bulletdelete(soft_body_world_info);
+}
+
+void SpaceBullet::check_ghost_overlaps() {
+
+ /// Algorith support variables
+ btGjkEpaPenetrationDepthSolver gjk_epa_pen_solver;
+ btVoronoiSimplexSolver gjk_simplex_solver;
+ gjk_simplex_solver.setEqualVertexThreshold(0.f);
+ btConvexShape *other_body_shape;
+ btConvexShape *area_shape;
+ btGjkPairDetector::ClosestPointInput gjk_input;
+ AreaBullet *area;
+ RigidCollisionObjectBullet *otherObject;
+ int x(-1), i(-1), y(-1), z(-1), indexOverlap(-1);
+
+ /// For each areas
+ for (x = areas.size() - 1; 0 <= x; --x) {
+ area = areas[x];
+
+ if (!area->is_monitoring())
+ continue;
+
+ /// 1. Reset all states
+ for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) {
+ AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects[i];
+ // This check prevent the overwrite of ENTER state
+ // if this function is called more times before dispatchCallbacks
+ if (otherObj.state != AreaBullet::OVERLAP_STATE_ENTER) {
+ otherObj.state = AreaBullet::OVERLAP_STATE_DIRTY;
+ }
+ }
+
+ /// 2. Check all overlapping objects using GJK
+
+ const btAlignedObjectArray<btCollisionObject *> ghostOverlaps = area->get_bt_ghost()->getOverlappingPairs();
+
+ // For each overlapping
+ for (i = ghostOverlaps.size() - 1; 0 <= i; --i) {
+
+ if (!(ghostOverlaps[i]->getUserIndex() == CollisionObjectBullet::TYPE_RIGID_BODY || ghostOverlaps[i]->getUserIndex() == CollisionObjectBullet::TYPE_AREA))
+ continue;
+
+ otherObject = static_cast<RigidCollisionObjectBullet *>(ghostOverlaps[i]->getUserPointer());
+
+ bool hasOverlap = false;
+
+ // For each area shape
+ for (y = area->get_compound_shape()->getNumChildShapes() - 1; 0 <= y; --y) {
+ if (!area->get_compound_shape()->getChildShape(y)->isConvex())
+ continue;
+
+ gjk_input.m_transformA = area->get_transform__bullet() * area->get_compound_shape()->getChildTransform(y);
+ area_shape = static_cast<btConvexShape *>(area->get_compound_shape()->getChildShape(y));
+
+ // For each other object shape
+ for (z = otherObject->get_compound_shape()->getNumChildShapes() - 1; 0 <= z; --z) {
+
+ if (!otherObject->get_compound_shape()->getChildShape(z)->isConvex())
+ continue;
+
+ other_body_shape = static_cast<btConvexShape *>(otherObject->get_compound_shape()->getChildShape(z));
+ gjk_input.m_transformB = otherObject->get_transform__bullet() * otherObject->get_compound_shape()->getChildTransform(z);
+
+ btPointCollector result;
+ btGjkPairDetector gjk_pair_detector(area_shape, other_body_shape, &gjk_simplex_solver, &gjk_epa_pen_solver);
+ gjk_pair_detector.getClosestPoints(gjk_input, result, 0);
+
+ if (0 >= result.m_distance) {
+ hasOverlap = true;
+ goto collision_found;
+ }
+ } // ~For each other object shape
+ } // ~For each area shape
+
+ collision_found:
+ if (!hasOverlap)
+ continue;
+
+ indexOverlap = area->find_overlapping_object(otherObject);
+ if (-1 == indexOverlap) {
+ // Not found
+ area->add_overlap(otherObject);
+ } else {
+ // Found
+ area->put_overlap_as_inside(indexOverlap);
+ }
+ }
+
+ /// 3. Remove not overlapping
+ for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) {
+ // If the overlap has DIRTY state it means that it's no more overlapping
+ if (area->overlappingObjects[i].state == AreaBullet::OVERLAP_STATE_DIRTY) {
+ area->put_overlap_as_exit(i);
+ }
+ }
+ }
+}
+
+void SpaceBullet::check_body_collision() {
+#ifdef DEBUG_ENABLED
+ reset_debug_contact_count();
+#endif
+
+ const int numManifolds = dynamicsWorld->getDispatcher()->getNumManifolds();
+ for (int i = 0; i < numManifolds; ++i) {
+ btPersistentManifold *contactManifold = dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
+ const btCollisionObject *obA = contactManifold->getBody0();
+ const btCollisionObject *obB = contactManifold->getBody1();
+
+ if (btCollisionObject::CO_RIGID_BODY != obA->getInternalType() || btCollisionObject::CO_RIGID_BODY != obB->getInternalType()) {
+ // This checks is required to be sure the ghost object is skipped
+ // The ghost object "getUserPointer" return the BodyBullet owner so this check is required
+ continue;
+ }
+
+ // Asserts all Godot objects are assigned
+ assert(NULL != obA->getUserPointer());
+ assert(NULL != obB->getUserPointer());
+
+ // I know this static cast is a bit risky. But I'm checking its type just after it.
+ // This allow me to avoid a lot of other cast and checks
+ RigidBodyBullet *bodyA = static_cast<RigidBodyBullet *>(obA->getUserPointer());
+ RigidBodyBullet *bodyB = static_cast<RigidBodyBullet *>(obB->getUserPointer());
+
+ if (CollisionObjectBullet::TYPE_RIGID_BODY == bodyA->getType() && CollisionObjectBullet::TYPE_RIGID_BODY == bodyB->getType()) {
+ if (!bodyA->can_add_collision() && !bodyB->can_add_collision()) {
+ continue;
+ }
+
+ const int numContacts = contactManifold->getNumContacts();
+#define REPORT_ALL_CONTACTS 0
+#if REPORT_ALL_CONTACTS
+ for (int j = 0; j < numContacts; j++) {
+ btManifoldPoint &pt = contactManifold->getContactPoint(j);
+#else
+ // Since I don't need report all contacts for these objects, I'll report only the first
+ if (numContacts) {
+ btManifoldPoint &pt = contactManifold->getContactPoint(0);
+#endif
+ Vector3 collisionWorldPosition;
+ Vector3 collisionLocalPosition;
+ Vector3 normalOnB;
+ B_TO_G(pt.m_normalWorldOnB, normalOnB);
+
+ 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() - obB->getWorldTransform().getOrigin(), collisionLocalPosition);
+ bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, pt.m_index1, pt.m_index0);
+ }
+ 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() - obA->getWorldTransform().getOrigin(), collisionLocalPosition);
+ bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, pt.m_index0, pt.m_index1);
+ }
+
+#ifdef DEBUG_ENABLED
+ if (is_debugging_contacts()) {
+ add_debug_contact(collisionWorldPosition);
+ }
+#endif
+ }
+ }
+ }
+}
+
+void SpaceBullet::update_gravity() {
+ btVector3 btGravity;
+ G_TO_B(gravityDirection * gravityMagnitude, btGravity);
+ dynamicsWorld->setGravity(btGravity);
+ if (soft_body_world_info) {
+ soft_body_world_info->m_gravity = btGravity;
+ }
+}
+
+/// IMPORTANT: Please don't turn it ON this is not managed correctly!!
+/// I'm leaving this here just for future tests.
+/// Debug motion and normal vector drawing
+#define debug_test_motion 0
+#if debug_test_motion
+static ImmediateGeometry *motionVec(NULL);
+static ImmediateGeometry *normalLine(NULL);
+static Ref<SpatialMaterial> red_mat;
+static Ref<SpatialMaterial> blue_mat;
+#endif
+
+#define IGNORE_AREAS_TRUE true
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer::MotionResult *r_result) {
+
+#if debug_test_motion
+ /// Yes I know this is not good, but I've used it as fast debugging.
+ /// I'm leaving it here just for speedup the other eventual debugs
+ if (!normalLine) {
+ motionVec = memnew(ImmediateGeometry);
+ normalLine = memnew(ImmediateGeometry);
+ SceneTree::get_singleton()->get_current_scene()->add_child(motionVec);
+ SceneTree::get_singleton()->get_current_scene()->add_child(normalLine);
+
+ red_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+ red_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ red_mat->set_line_width(20.0);
+ red_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ red_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ red_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ red_mat->set_albedo(Color(1, 0, 0, 1));
+ motionVec->set_material_override(red_mat);
+
+ blue_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial));
+ blue_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
+ blue_mat->set_line_width(20.0);
+ blue_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ blue_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ blue_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ blue_mat->set_albedo(Color(0, 0, 1, 1));
+ normalLine->set_material_override(blue_mat);
+ }
+#endif
+
+ ///// Release all generated manifolds
+ //{
+ // if(p_body->get_kinematic_utilities()){
+ // for(int i= p_body->get_kinematic_utilities()->m_generatedManifold.size()-1; 0<=i; --i){
+ // dispatcher->releaseManifold( p_body->get_kinematic_utilities()->m_generatedManifold[i] );
+ // }
+ // p_body->get_kinematic_utilities()->m_generatedManifold.clear();
+ // }
+ //}
+
+ btVector3 recover_initial_position;
+ recover_initial_position.setZero();
+
+/// I'm performing the unstack at the end of movement so I'm sure the player is unstacked even after the movement.
+/// I've removed the initial unstack because this is useful just for the first tick since after the first
+/// the real unstack is performed at the end of process.
+/// However I'm leaving here the old code.
+/// Note: It has a bug when two shapes touches something simultaneously the body is moved too much away (I'm not fixing it for the reason written above).
+#define INITIAL_UNSTACK 0
+#if !INITIAL_UNSTACK
+ btTransform body_safe_position;
+ G_TO_B(p_from, body_safe_position);
+//btTransform body_unsafe_positino;
+//G_TO_B(p_from, body_unsafe_positino);
+#else
+ btTransform body_safe_position;
+ btTransform body_unsafe_positino;
+ { /// Phase one - multi shapes depenetration using margin
+ G_TO_B(p_from, body_safe_position);
+ G_TO_B(p_from, body_unsafe_positino);
+
+ // MAX_PENETRATION_DEPTH Is useful have the ghost a bit penetrated so I can detect the floor easily
+ recover_from_penetration(p_body, body_safe_position, MAX_PENETRATION_DEPTH, /* p_depenetration_speed */ 1, recover_initial_position);
+
+ /// Not required if I put p_depenetration_speed = 1
+ //for(int t = 0; t<4; ++t){
+ // if(!recover_from_penetration(p_body, body_safe_position, MAX_PENETRATION_DEPTH, /* p_depenetration_speed */0.2, recover_initial_position)){
+ // break;
+ // }
+ //}
+
+ // Add recover position to "From" and "To" transforms
+ body_safe_position.getOrigin() += recover_initial_position;
+ }
+#endif
+
+ int shape_most_recovered(-1);
+ btVector3 recovered_motion;
+ G_TO_B(p_motion, recovered_motion);
+ const int shape_count(p_body->get_shape_count());
+
+ { /// phase two - sweep test, from a secure position without margin
+
+#if debug_test_motion
+ Vector3 sup_line;
+ B_TO_G(body_safe_position.getOrigin(), sup_line);
+ motionVec->clear();
+ motionVec->begin(Mesh::PRIMITIVE_LINES, NULL);
+ motionVec->add_vertex(sup_line);
+ motionVec->add_vertex(sup_line + p_motion * 10);
+ motionVec->end();
+#endif
+
+ for (int shIndex = 0; shIndex < shape_count; ++shIndex) {
+ if (p_body->is_shape_disabled(shIndex)) {
+ continue;
+ }
+
+ btConvexShape *convex_shape_test(dynamic_cast<btConvexShape *>(p_body->get_bt_shape(shIndex)));
+ if (!convex_shape_test) {
+ // Skip no convex shape
+ continue;
+ }
+
+ btTransform shape_xform_from;
+ G_TO_B(p_body->get_shape_transform(shIndex), shape_xform_from);
+ //btTransform shape_xform_to(shape_xform_from);
+
+ // Add local shape transform
+ shape_xform_from.getOrigin() += body_safe_position.getOrigin();
+ shape_xform_from.getBasis() *= body_safe_position.getBasis();
+
+ btTransform shape_xform_to(shape_xform_from);
+ //shape_xform_to.getOrigin() += body_unsafe_positino.getOrigin();
+ //shape_xform_to.getBasis() *= body_unsafe_positino.getBasis();
+ shape_xform_to.getOrigin() += recovered_motion;
+
+ GodotKinClosestConvexResultCallback btResult(shape_xform_from.getOrigin(), shape_xform_to.getOrigin(), p_body, IGNORE_AREAS_TRUE);
+ btResult.m_collisionFilterGroup = p_body->get_collision_layer();
+ btResult.m_collisionFilterMask = p_body->get_collision_mask();
+
+ dynamicsWorld->convexSweepTest(convex_shape_test, shape_xform_from, shape_xform_to, btResult);
+
+ if (btResult.hasHit()) {
+ //recovered_motion *= btResult.m_closestHitFraction;
+ /// Since for each sweep test I fix the motion of new shapes in base the recover result,
+ /// if another shape will hit something it means that has a deepest recovering respect the previous shape
+ shape_most_recovered = shIndex;
+ }
+ }
+ }
+
+ bool hasHit = false;
+
+ { /// Phase three - contact test with margin
+
+ btGhostObject *ghost = p_body->get_kinematic_utilities()->m_ghostObject;
+
+ GodotRecoverAndClosestContactResultCallback result_callabck;
+
+ if (false && 0 <= shape_most_recovered) {
+ result_callabck.m_self_object = p_body;
+ result_callabck.m_ignore_areas = IGNORE_AREAS_TRUE;
+ result_callabck.m_collisionFilterGroup = p_body->get_collision_layer();
+ result_callabck.m_collisionFilterMask = p_body->get_collision_mask();
+
+ const RigidBodyBullet::KinematicShape &kin(p_body->get_kinematic_utilities()->m_shapes[shape_most_recovered]);
+ ghost->setCollisionShape(kin.shape);
+ ghost->setWorldTransform(body_safe_position);
+
+ ghost->getWorldTransform().getOrigin() += recovered_motion;
+ ghost->getWorldTransform().getOrigin() += kin.transform.getOrigin();
+ ghost->getWorldTransform().getBasis() *= kin.transform.getBasis();
+
+ dynamicsWorld->contactTest(ghost, result_callabck);
+
+ recovered_motion += result_callabck.m_recover_penetration; // Required to avoid all kind of penetration
+
+ } else {
+ // The sweep result does not return a penetrated shape, so I've to check all shapes
+ // Then return the most penetrated shape
+
+ GodotRecoverAndClosestContactResultCallback iter_result_callabck(p_body, IGNORE_AREAS_TRUE);
+ iter_result_callabck.m_collisionFilterGroup = p_body->get_collision_layer();
+ iter_result_callabck.m_collisionFilterMask = p_body->get_collision_mask();
+
+ btScalar max_penetration(99999999999);
+ for (int i = 0; i < shape_count; ++i) {
+
+ const RigidBodyBullet::KinematicShape &kin(p_body->get_kinematic_utilities()->m_shapes[i]);
+ if (!kin.is_active()) {
+ continue;
+ }
+
+ // reset callback each function
+ iter_result_callabck.reset();
+
+ ghost->setCollisionShape(kin.shape);
+ ghost->setWorldTransform(body_safe_position);
+ ghost->getWorldTransform().getOrigin() += recovered_motion;
+ ghost->getWorldTransform().getOrigin() += kin.transform.getOrigin();
+ ghost->getWorldTransform().getBasis() *= kin.transform.getBasis();
+
+ dynamicsWorld->contactTest(ghost, iter_result_callabck);
+
+ if (iter_result_callabck.hasHit()) {
+ if (max_penetration > iter_result_callabck.m_penetration_distance) {
+ max_penetration = iter_result_callabck.m_penetration_distance;
+ shape_most_recovered = i;
+ // This is more penetrated
+ result_callabck.m_pointCollisionObject = iter_result_callabck.m_pointCollisionObject;
+ result_callabck.m_pointNormalWorld = iter_result_callabck.m_pointNormalWorld;
+ result_callabck.m_pointWorld = iter_result_callabck.m_pointWorld;
+ result_callabck.m_penetration_distance = iter_result_callabck.m_penetration_distance;
+ result_callabck.m_other_compound_shape_index = iter_result_callabck.m_other_compound_shape_index;
+
+ recovered_motion += iter_result_callabck.m_recover_penetration; // Required to avoid all kind of penetration
+ }
+ }
+ }
+ }
+
+ hasHit = result_callabck.hasHit();
+
+ if (r_result) {
+
+ B_TO_G(recovered_motion + recover_initial_position, r_result->motion);
+
+ if (hasHit) {
+
+ if (btCollisionObject::CO_RIGID_BODY != result_callabck.m_pointCollisionObject->getInternalType()) {
+ ERR_PRINT("The collision is not against a rigid body. Please check what's going on.");
+ goto EndExecution;
+ }
+ const btRigidBody *btRigid = static_cast<const btRigidBody *>(result_callabck.m_pointCollisionObject);
+ CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(btRigid->getUserPointer());
+
+ r_result->remainder = p_motion - r_result->motion; // is the remaining movements
+ B_TO_G(result_callabck.m_pointWorld, r_result->collision_point);
+ B_TO_G(result_callabck.m_pointNormalWorld, r_result->collision_normal);
+ B_TO_G(btRigid->getVelocityInLocalPoint(result_callabck.m_pointWorld - btRigid->getWorldTransform().getOrigin()), r_result->collider_velocity); // It calculates velocity at point and assign it using special function Bullet_to_Godot
+ r_result->collider = collisionObject->get_self();
+ r_result->collider_id = collisionObject->get_instance_id();
+ r_result->collider_shape = result_callabck.m_other_compound_shape_index;
+ r_result->collision_local_shape = shape_most_recovered;
+
+//{ /// Add manifold point to manage collisions
+// btPersistentManifold* manifold = dynamicsWorld->getDispatcher()->getNewManifold(p_body->getBtBody(), btRigid);
+// btManifoldPoint manifoldPoint(result_callabck.m_pointWorld, result_callabck.m_pointWorld, result_callabck.m_pointNormalWorld, result_callabck.m_penetration_distance);
+// manifoldPoint.m_index0 = r_result->collision_local_shape;
+// manifoldPoint.m_index1 = r_result->collider_shape;
+// manifold->addManifoldPoint(manifoldPoint);
+// p_body->get_kinematic_utilities()->m_generatedManifold.push_back(manifold);
+//}
+
+#if debug_test_motion
+ Vector3 sup_line2;
+ B_TO_G(recovered_motion, sup_line2);
+ //Vector3 sup_pos;
+ //B_TO_G( pt.getPositionWorldOnB(), sup_pos);
+ normalLine->clear();
+ normalLine->begin(Mesh::PRIMITIVE_LINES, NULL);
+ normalLine->add_vertex(r_result->collision_point);
+ normalLine->add_vertex(r_result->collision_point + r_result->collision_normal * 10);
+ normalLine->end();
+#endif
+
+ } else {
+ r_result->remainder = Vector3();
+ }
+ }
+ }
+
+EndExecution:
+ p_body->get_kinematic_utilities()->resetDefShape();
+ return hasHit;
+}
+
+/// Note: It has a bug when two shapes touches something simultaneously the body is moved too much away
+/// (I'm not fixing it because I don't use it).
+bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_maxPenetrationDepth, btScalar p_depenetration_speed, btVector3 &out_recover_position) {
+
+ bool penetration = false;
+ btPairCachingGhostObject *ghost = p_body->get_kinematic_utilities()->m_ghostObject;
+
+ for (int kinIndex = p_body->get_kinematic_utilities()->m_shapes.size() - 1; 0 <= kinIndex; --kinIndex) {
+ const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->m_shapes[kinIndex]);
+ if (!kin_shape.is_active()) {
+ continue;
+ }
+
+ btConvexShape *convexShape = kin_shape.shape;
+ btTransform shape_xform(kin_shape.transform);
+
+ // from local to world
+ shape_xform.getOrigin() += p_from.getOrigin();
+ shape_xform.getBasis() *= p_from.getBasis();
+
+ // Apply last recovery to avoid doubling the recovering
+ shape_xform.getOrigin() += out_recover_position;
+
+ ghost->setCollisionShape(convexShape);
+ ghost->setWorldTransform(shape_xform);
+
+ btVector3 minAabb, maxAabb;
+ convexShape->getAabb(shape_xform, minAabb, maxAabb);
+ dynamicsWorld->getBroadphase()->setAabb(ghost->getBroadphaseHandle(),
+ minAabb,
+ maxAabb,
+ dynamicsWorld->getDispatcher());
+
+ dynamicsWorld->getDispatcher()->dispatchAllCollisionPairs(ghost->getOverlappingPairCache(), dynamicsWorld->getDispatchInfo(), dynamicsWorld->getDispatcher());
+
+ for (int i = 0; i < ghost->getOverlappingPairCache()->getNumOverlappingPairs(); ++i) {
+ p_body->get_kinematic_utilities()->m_manifoldArray.resize(0);
+
+ btBroadphasePair *collisionPair = &ghost->getOverlappingPairCache()->getOverlappingPairArray()[i];
+
+ btCollisionObject *obj0 = static_cast<btCollisionObject *>(collisionPair->m_pProxy0->m_clientObject);
+ btCollisionObject *obj1 = static_cast<btCollisionObject *>(collisionPair->m_pProxy1->m_clientObject);
+
+ if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse()))
+ continue;
+
+ // This is not required since the dispatched does all the job
+ //if (!needsCollision(obj0, obj1))
+ // continue;
+
+ if (collisionPair->m_algorithm)
+ collisionPair->m_algorithm->getAllContactManifolds(p_body->get_kinematic_utilities()->m_manifoldArray);
+
+ for (int j = 0; j < p_body->get_kinematic_utilities()->m_manifoldArray.size(); ++j) {
+
+ btPersistentManifold *manifold = p_body->get_kinematic_utilities()->m_manifoldArray[j];
+ btScalar directionSign = manifold->getBody0() == ghost ? btScalar(-1.0) : btScalar(1.0);
+ for (int p = 0; p < manifold->getNumContacts(); ++p) {
+ const btManifoldPoint &pt = manifold->getContactPoint(p);
+
+ btScalar dist = pt.getDistance();
+ if (dist < -p_maxPenetrationDepth) {
+ penetration = true;
+ out_recover_position += pt.m_normalWorldOnB * directionSign * (dist + p_maxPenetrationDepth) * p_depenetration_speed;
+ //print_line("penetrate distance: " + rtos(dist));
+ }
+ //else {
+ // print_line("touching distance: " + rtos(dist));
+ //}
+ }
+ }
+ }
+ }
+
+ p_body->get_kinematic_utilities()->resetDefShape();
+ return penetration;
+}
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
new file mode 100644
index 0000000000..b36896650b
--- /dev/null
+++ b/modules/bullet/space_bullet.h
@@ -0,0 +1,177 @@
+/*************************************************************************/
+/* space_bullet.h */
+/* Author: AndreaCatania */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SPACE_BULLET_H
+#define SPACE_BULLET_H
+
+#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
+#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
+#include "LinearMath/btScalar.h"
+#include "LinearMath/btTransform.h"
+#include "LinearMath/btVector3.h"
+#include "core/variant.h"
+#include "core/vector.h"
+#include "godot_result_callbacks.h"
+#include "rid_bullet.h"
+#include "servers/physics_server.h"
+
+class AreaBullet;
+class btBroadphaseInterface;
+class btCollisionDispatcher;
+class btConstraintSolver;
+class btDefaultCollisionConfiguration;
+class btDynamicsWorld;
+class btDiscreteDynamicsWorld;
+class btEmptyShape;
+class btGhostPairCallback;
+class btSoftRigidDynamicsWorld;
+class btSoftBodyWorldInfo;
+class ConstraintBullet;
+class CollisionObjectBullet;
+class RigidBodyBullet;
+class SpaceBullet;
+class SoftBodyBullet;
+
+class BulletPhysicsDirectSpaceState : public PhysicsDirectSpaceState {
+ GDCLASS(BulletPhysicsDirectSpaceState, PhysicsDirectSpaceState)
+private:
+ SpaceBullet *space;
+
+public:
+ BulletPhysicsDirectSpaceState(SpaceBullet *p_space);
+
+ virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION);
+ 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_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, bool p_pick_ray = false);
+ virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION);
+ virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION, ShapeRestInfo *r_info = NULL);
+ /// 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_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION);
+ 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_layer = 0xFFFFFFFF, uint32_t p_object_type_mask = TYPE_MASK_COLLISION);
+ virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const;
+};
+
+class SpaceBullet : public RIDBullet {
+private:
+ friend class AreaBullet;
+ friend void onBulletTickCallback(btDynamicsWorld *world, btScalar timeStep);
+ friend class BulletPhysicsDirectSpaceState;
+
+ btBroadphaseInterface *broadphase;
+ btDefaultCollisionConfiguration *collisionConfiguration;
+ btCollisionDispatcher *dispatcher;
+ btConstraintSolver *solver;
+ btDiscreteDynamicsWorld *dynamicsWorld;
+ btGhostPairCallback *ghostPairCallback;
+ GodotFilterCallback *godotFilterCallback;
+ btSoftBodyWorldInfo *soft_body_world_info;
+
+ BulletPhysicsDirectSpaceState *direct_access;
+ Vector3 gravityDirection;
+ real_t gravityMagnitude;
+
+ Vector<AreaBullet *> areas;
+
+ Vector<Vector3> contactDebug;
+ int contactDebugCount;
+
+public:
+ SpaceBullet(bool p_create_soft_world);
+ virtual ~SpaceBullet();
+
+ void flush_queries();
+ void step(real_t p_delta_time);
+
+ _FORCE_INLINE_ btBroadphaseInterface *get_broadphase() { return broadphase; }
+ _FORCE_INLINE_ btCollisionDispatcher *get_dispatcher() { return dispatcher; }
+ _FORCE_INLINE_ btSoftBodyWorldInfo *get_soft_body_world_info() { return soft_body_world_info; }
+ _FORCE_INLINE_ bool is_using_soft_world() { return soft_body_world_info; }
+
+ /// Used to set some parameters to Bullet world
+ /// @param p_param:
+ /// AREA_PARAM_GRAVITY to set the gravity magnitude of entire world
+ /// AREA_PARAM_GRAVITY_VECTOR to set the gravity direction of entire world
+ void set_param(PhysicsServer::AreaParameter p_param, const Variant &p_value);
+ /// Used to get some parameters to Bullet world
+ /// @param p_param:
+ /// AREA_PARAM_GRAVITY to get the gravity magnitude of entire world
+ /// AREA_PARAM_GRAVITY_VECTOR to get the gravity direction of entire world
+ Variant get_param(PhysicsServer::AreaParameter p_param);
+
+ void set_param(PhysicsServer::SpaceParameter p_param, real_t p_value);
+ real_t get_param(PhysicsServer::SpaceParameter p_param);
+
+ void add_area(AreaBullet *p_area);
+ void remove_area(AreaBullet *p_area);
+ void reload_collision_filters(AreaBullet *p_area);
+
+ void add_rigid_body(RigidBodyBullet *p_body);
+ void remove_rigid_body(RigidBodyBullet *p_body);
+ void reload_collision_filters(RigidBodyBullet *p_body);
+
+ void add_soft_body(SoftBodyBullet *p_body);
+ void remove_soft_body(SoftBodyBullet *p_body);
+ void reload_collision_filters(SoftBodyBullet *p_body);
+
+ void add_constraint(ConstraintBullet *p_constraint, bool disableCollisionsBetweenLinkedBodies = false);
+ void remove_constraint(ConstraintBullet *p_constraint);
+
+ int get_num_collision_objects() const;
+ void remove_all_collision_objects();
+
+ 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_ void reset_debug_contact_count() {
+ contactDebugCount = 0;
+ }
+ _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) {
+ if (contactDebugCount < contactDebug.size()) contactDebug[contactDebugCount++] = p_contact;
+ }
+ _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contactDebug; }
+ _FORCE_INLINE_ int get_debug_contact_count() { return contactDebugCount; }
+
+ const Vector3 &get_gravity_direction() const { return gravityDirection; }
+ real_t get_gravity_magnitude() const { return gravityMagnitude; }
+
+ void update_gravity();
+
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer::MotionResult *r_result);
+
+private:
+ void create_empty_world(bool p_create_soft_world);
+ void destroy_world();
+ void check_ghost_overlaps();
+ void check_body_collision();
+
+ bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_from, btScalar p_maxPenetrationDepth, btScalar p_depenetration_speed, btVector3 &out_recover_position);
+};
+#endif
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 95d93e6af6..ae9daa802f 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -152,7 +152,7 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
*/
//must avoid this later
- while (f->get_pos() < 128)
+ while (f->get_position() < 128)
f->get_8();
DDSFormat dds_format;
diff --git a/modules/enet/SCsub b/modules/enet/SCsub
index 42a933a66d..4790c5099f 100644
--- a/modules/enet/SCsub
+++ b/modules/enet/SCsub
@@ -7,7 +7,7 @@ Import('env_modules')
env_enet = env_modules.Clone()
-if (env['builtin_enet'] != 'no'):
+if env['builtin_enet']:
thirdparty_dir = "#thirdparty/enet/"
thirdparty_sources = [
"godot.cpp",
diff --git a/modules/etc/config.py b/modules/etc/config.py
index 4b0b01b78e..7dc2cb59c1 100644
--- a/modules/etc/config.py
+++ b/modules/etc/config.py
@@ -6,6 +6,6 @@ def can_build(platform):
def configure(env):
# Tools only, disabled for non-tools
# TODO: Find a cleaner way to achieve that
- if (env["tools"] == "no"):
- env["module_etc_enabled"] = "no"
+ if not env['tools']:
+ env['module_etc_enabled'] = False
env.disabled_modules.append("etc")
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index f22df4407c..19e384af73 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -6,7 +6,7 @@ from compat import isbasestring
# Not building in a separate env as scene needs it
# Thirdparty source files
-if (env['builtin_freetype'] != 'no'):
+if env['builtin_freetype']:
thirdparty_dir = "#thirdparty/freetype/"
thirdparty_sources = [
"src/autofit/autofit.c",
@@ -65,7 +65,7 @@ if (env['builtin_freetype'] != 'no'):
env.Append(CPPPATH=[thirdparty_dir, thirdparty_dir + "/include"])
# also requires libpng headers
- if (env['builtin_libpng'] != 'no'):
+ if env['builtin_libpng']:
env.Append(CPPPATH=["#thirdparty/libpng"])
lib = env.Library("freetype_builtin", thirdparty_sources)
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index f386f2b542..a6ae143947 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -4,14 +4,155 @@ Import('env')
gdn_env = env.Clone()
-gdn_env.add_source_files(env.modules_sources, "*.cpp")
+gdn_env.add_source_files(env.modules_sources, "gd_native_library_editor.cpp")
+gdn_env.add_source_files(env.modules_sources, "gdnative.cpp")
+gdn_env.add_source_files(env.modules_sources, "register_types.cpp")
gdn_env.add_source_files(env.modules_sources, "gdnative/*.cpp")
gdn_env.add_source_files(env.modules_sources, "nativescript/*.cpp")
-gdn_env.Append(CPPFLAGS=['-DGDAPI_BUILT_IN'])
gdn_env.Append(CPPPATH=['#modules/gdnative/include/'])
-if "platform" in env and env["platform"] == "x11": # there has to be a better solution?
- env.Append(LINKFLAGS=["-rdynamic"])
+SConscript("nativearvr/SCsub")
+SConscript("pluginscript/SCsub")
+
+def _spaced(e):
+ return e if e[-1] == '*' else e + ' '
+
+def _build_gdnative_api_struct_header(api):
+ out = [
+ '/* THIS FILE IS GENERATED DO NOT EDIT */',
+ '#ifndef GODOT_GDNATIVE_API_STRUCT_H',
+ '#define GODOT_GDNATIVE_API_STRUCT_H',
+ '',
+ '#include <gdnative/gdnative.h>',
+ '#include <nativearvr/godot_nativearvr.h>',
+ '#include <nativescript/godot_nativescript.h>',
+ '#include <pluginscript/godot_pluginscript.h>',
+ '',
+ '#define GDNATIVE_API_INIT(options) do { extern const godot_gdnative_api_struct *_gdnative_wrapper_api_struct; _gdnative_wrapper_api_struct = options->api_struct; } while (0)',
+ '',
+ '#ifdef __cplusplus',
+ 'extern "C" {',
+ '#endif',
+ '',
+ 'typedef struct godot_gdnative_api_struct {',
+ '\tvoid *next;',
+ '\tconst char *version;',
+ ]
+
+ for funcdef in api['api']:
+ args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']])
+ out.append('\t%s(*%s)(%s);' % (_spaced(funcdef['return_type']), funcdef['name'], args))
+
+ out += [
+ '} godot_gdnative_api_struct;',
+ '',
+ '#ifdef __cplusplus',
+ '}',
+ '#endif',
+ '',
+ '#endif // GODOT_GDNATIVE_API_STRUCT_H',
+ ''
+ ]
+ return '\n'.join(out)
+
+def _build_gdnative_api_struct_source(api):
+ out = [
+ '/* THIS FILE IS GENERATED DO NOT EDIT */',
+ '',
+ '#include <gdnative_api_struct.gen.h>',
+ '',
+ 'const char *_gdnative_api_version = "%s";' % api['version'],
+ 'extern const godot_gdnative_api_struct api_struct = {',
+ '\tNULL,',
+ '\t_gdnative_api_version,',
+ ]
+
+ for funcdef in api['api']:
+ out.append('\t%s,' % funcdef['name'])
+ out.append('};\n')
+
+ return '\n'.join(out)
+
+def build_gdnative_api_struct(target, source, env):
+ import json
+ from collections import OrderedDict
+
+ with open(source[0].path, 'r') as fd:
+ api = json.load(fd)
+
+ header, source = target
+ with open(header.path, 'w') as fd:
+ fd.write(_build_gdnative_api_struct_header(api))
+ with open(source.path, 'w') as fd:
+ fd.write(_build_gdnative_api_struct_source(api))
+
+_, gensource = gdn_env.Command(['include/gdnative_api_struct.gen.h', 'gdnative_api_struct.gen.cpp'],
+ 'gdnative_api.json', build_gdnative_api_struct)
+gdn_env.add_source_files(env.modules_sources, [gensource])
env.use_ptrcall = True
+
+
+def _build_gdnative_wrapper_code(api):
+ out = [
+ '/* THIS FILE IS GENERATED DO NOT EDIT */',
+ '',
+ '#include <gdnative/gdnative.h>',
+ '#include <nativescript/godot_nativescript.h>',
+ '#include <pluginscript/godot_pluginscript.h>',
+ '',
+ '#include <gdnative_api_struct.gen.h>',
+ '',
+ 'godot_gdnative_api_struct *_gdnative_wrapper_api_struct = 0;',
+ '',
+ '#ifdef __cplusplus',
+ 'extern "C" {',
+ '#endif',
+ ''
+ ]
+
+ for funcdef in api['api']:
+ args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']])
+ out.append('%s%s(%s) {' % (_spaced(funcdef['return_type']), funcdef['name'], args))
+
+ args = ', '.join(['%s' % n for t, n in funcdef['arguments']])
+
+ return_line = '\treturn ' if funcdef['return_type'] != 'void' else '\t'
+ return_line += '_gdnative_wrapper_api_struct->' + funcdef['name'] + '(' + args + ');'
+
+ out.append(return_line)
+ out.append('}')
+ out.append('')
+
+ out += [
+ '#ifdef __cplusplus',
+ '}',
+ '#endif'
+ ]
+
+ return '\n'.join(out)
+
+
+def build_gdnative_wrapper_code(target, source, env):
+ import json
+ with open(source[0].path, 'r') as fd:
+ api = json.load(fd)
+
+ wrapper_file = target[0]
+ with open(wrapper_file.path, 'w') as fd:
+ fd.write(_build_gdnative_wrapper_code(api))
+
+
+
+if ARGUMENTS.get('gdnative_wrapper', False):
+ #build wrapper code
+ gensource, = gdn_env.Command('gdnative_wrapper_code.gen.cpp', 'gdnative_api.json', build_gdnative_wrapper_code)
+
+ gd_wrapper_env = env.Clone()
+ gd_wrapper_env.Append(CPPPATH=['#modules/gdnative/include/'])
+
+ # I think this doesn't work on MSVC yet...
+ gd_wrapper_env.Append(CCFLAGS=['-fPIC'])
+
+ gd_wrapper_env.Library("#bin/gdnative_wrapper_code", [gensource])
diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py
index 9f57b9bb74..df3556249d 100644
--- a/modules/gdnative/config.py
+++ b/modules/gdnative/config.py
@@ -1,8 +1,12 @@
-
def can_build(platform):
return True
-
def configure(env):
env.use_ptrcall = True
+
+def get_doc_classes():
+ return ["GDNative", "GDNativeLibrary", "NativeScript", "ARVRInterfaceGDNative"]
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
new file mode 100644
index 0000000000..308a7d5946
--- /dev/null
+++ b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ GDNative wrapper for an ARVR interface
+ </brief_description>
+ <description>
+ This is a wrapper class for GDNative implementations of the ARVR interface. To use a GDNative ARVR interface simply instantiate this object and set your GDNative library containing the ARVR interface implementation.
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml
new file mode 100644
index 0000000000..83a1cf06f0
--- /dev/null
+++ b/modules/gdnative/doc_classes/GDNative.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GDNative" inherits="Reference" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ <method name="call_native">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="calling_type" type="String">
+ </argument>
+ <argument index="1" name="procedure_name" type="String">
+ </argument>
+ <argument index="2" name="arguments" type="Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_library">
+ <return type="GDNativeLibrary">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="initialize">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_library">
+ <return type="void">
+ </return>
+ <argument index="0" name="library" type="GDNativeLibrary">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="terminate">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
new file mode 100644
index 0000000000..361c89e6b3
--- /dev/null
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ <method name="get_active_library_path" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_library_path" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="platform" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_singleton_gdnative" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_library_path">
+ <return type="void">
+ </return>
+ <argument index="0" name="platform" type="String">
+ </argument>
+ <argument index="1" name="path" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_singleton_gdnative">
+ <return type="void">
+ </return>
+ <argument index="0" name="singleton" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="singleton_gdnative" type="bool" setter="set_singleton_gdnative" getter="is_singleton_gdnative">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml
new file mode 100644
index 0000000000..b040cfd966
--- /dev/null
+++ b/modules/gdnative/doc_classes/NativeScript.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="NativeScript" inherits="Script" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ <method name="get_class_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_library" qualifiers="const">
+ <return type="GDNativeLibrary">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="new" qualifiers="vararg">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_class_name">
+ <return type="void">
+ </return>
+ <argument index="0" name="class_name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_library">
+ <return type="void">
+ </return>
+ <argument index="0" name="library" type="GDNativeLibrary">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="class_name" type="String" setter="set_class_name" getter="get_class_name">
+ </member>
+ <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/gdnative/gd_native_library_editor.cpp b/modules/gdnative/gd_native_library_editor.cpp
index cc2c2b69a6..c37b7f473d 100644
--- a/modules/gdnative/gd_native_library_editor.cpp
+++ b/modules/gdnative/gd_native_library_editor.cpp
@@ -72,7 +72,7 @@ void GDNativeLibraryEditor::_update_libraries() {
libraries->create_item(); //rppt
Vector<String> enabled_paths;
- if (ProjectSettings::get_singleton()->has("gdnative/singletons")) {
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
enabled_paths = ProjectSettings::get_singleton()->get("gdnative/singletons");
}
Set<String> enabled_list;
@@ -100,7 +100,7 @@ void GDNativeLibraryEditor::_item_edited() {
String path = item->get_metadata(0);
Vector<String> enabled_paths;
- if (ProjectSettings::get_singleton()->has("gdnative/singletons")) {
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
enabled_paths = ProjectSettings::get_singleton()->get("gdnative/singletons");
}
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 8cc8b0bec8..3fc04a5498 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -40,15 +40,8 @@
const String init_symbol = "godot_gdnative_init";
const String terminate_symbol = "godot_gdnative_terminate";
-#define GDAPI_FUNC(name, ret_type, ...) .name = name,
-#define GDAPI_FUNC_VOID(name, ...) .name = name,
-
-const godot_gdnative_api_struct api_struct = {
- GODOT_GDNATIVE_API_FUNCTIONS
-};
-
-#undef GDAPI_FUNC
-#undef GDAPI_FUNC_VOID
+// Defined in gdnative_api_struct.gen.cpp
+extern const godot_gdnative_api_struct api_struct;
String GDNativeLibrary::platform_names[NUM_PLATFORMS + 1] = {
"X11_32bit",
@@ -110,6 +103,7 @@ GDNativeLibrary::~GDNativeLibrary() {
void GDNativeLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_library_path", "platform", "path"), &GDNativeLibrary::set_library_path);
ClassDB::bind_method(D_METHOD("get_library_path", "platform"), &GDNativeLibrary::get_library_path);
+ ClassDB::bind_method(D_METHOD("get_active_library_path"), &GDNativeLibrary::get_active_library_path);
ClassDB::bind_method(D_METHOD("is_singleton_gdnative"), &GDNativeLibrary::is_singleton_gdnative);
ClassDB::bind_method(D_METHOD("set_singleton_gdnative", "singleton"), &GDNativeLibrary::set_singleton_gdnative);
@@ -205,10 +199,7 @@ void GDNative::_bind_methods() {
ClassDB::bind_method(D_METHOD("initialize"), &GDNative::initialize);
ClassDB::bind_method(D_METHOD("terminate"), &GDNative::terminate);
- // TODO(karroffel): get_native_(raw_)call_types binding?
-
- // TODO(karroffel): make this a varargs function?
- ClassDB::bind_method(D_METHOD("call_native", "procedure_name", "arguments"), &GDNative::call_native);
+ ClassDB::bind_method(D_METHOD("call_native", "calling_type", "procedure_name", "arguments"), &GDNative::call_native);
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
}
@@ -234,18 +225,18 @@ bool GDNative::initialize() {
ERR_PRINT("No library set for this platform");
return false;
}
-
+#ifdef IPHONE_ENABLED
+ String path = lib_path.replace("res://", "dylibs/");
+#else
String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
+#endif
Error err = OS::get_singleton()->open_dynamic_library(path, native_handle);
if (err != OK) {
return false;
}
void *library_init;
- err = OS::get_singleton()->get_dynamic_library_symbol_handle(
- native_handle,
- init_symbol,
- library_init);
+ err = get_symbol(init_symbol, library_init);
if (err || !library_init) {
OS::get_singleton()->close_dynamic_library(native_handle);
@@ -265,6 +256,7 @@ bool GDNative::initialize() {
options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE);
options.gd_native_library = (godot_object *)(get_library().ptr());
+ options.active_library_path = (godot_string *)&path;
library_init_fpointer(&options);
@@ -279,11 +271,8 @@ bool GDNative::terminate() {
}
void *library_terminate;
- Error error = OS::get_singleton()->get_dynamic_library_symbol_handle(
- native_handle,
- terminate_symbol,
- library_terminate);
- if (error) {
+ Error error = get_symbol(terminate_symbol, library_terminate);
+ if (error || !library_terminate) {
OS::get_singleton()->close_dynamic_library(native_handle);
native_handle = NULL;
return true;
@@ -315,10 +304,6 @@ void GDNativeCallRegistry::register_native_call_type(StringName p_call_type, nat
native_calls.insert(p_call_type, p_callback);
}
-void GDNativeCallRegistry::register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback) {
- native_raw_calls.insert(p_raw_call_type, p_callback);
-}
-
Vector<StringName> GDNativeCallRegistry::get_native_call_types() {
Vector<StringName> call_types;
call_types.resize(native_calls.size());
@@ -331,18 +316,6 @@ Vector<StringName> GDNativeCallRegistry::get_native_call_types() {
return call_types;
}
-Vector<StringName> GDNativeCallRegistry::get_native_raw_call_types() {
- Vector<StringName> call_types;
- call_types.resize(native_raw_calls.size());
-
- size_t idx = 0;
- for (Map<StringName, native_raw_call_cb>::Element *E = native_raw_calls.front(); E; E = E->next(), idx++) {
- call_types[idx] = E->key();
- }
-
- return call_types;
-}
-
Variant GDNative::call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments) {
Map<StringName, native_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_calls.find(p_native_call_type);
@@ -351,20 +324,34 @@ Variant GDNative::call_native(StringName p_native_call_type, StringName p_proced
return Variant();
}
- String procedure_name = p_procedure_name;
- godot_variant result = E->get()(native_handle, (godot_string *)&procedure_name, (godot_array *)&p_arguments);
+ void *procedure_handle;
+
+ Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
+ native_handle,
+ p_procedure_name,
+ procedure_handle);
+
+ if (err != OK || procedure_handle == NULL) {
+ return Variant();
+ }
+
+ godot_variant result = E->get()(procedure_handle, (godot_array *)&p_arguments);
return *(Variant *)&result;
}
-void GDNative::call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return) {
+Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle) {
- Map<StringName, native_raw_call_cb>::Element *E = GDNativeCallRegistry::singleton->native_raw_calls.find(p_raw_call_type);
- if (!E) {
- ERR_PRINT((String("No handler for native raw call type \"" + p_raw_call_type) + "\" found").utf8().get_data());
- return;
+ if (native_handle == NULL) {
+ ERR_PRINT("No valid library handle, can't get symbol from GDNative object");
+ return ERR_CANT_OPEN;
}
- String procedure_name = p_procedure_name;
- E->get()(native_handle, (godot_string *)&procedure_name, data, num_args, args, r_return);
+ Error result = OS::get_singleton()->get_dynamic_library_symbol_handle(
+ native_handle,
+ p_procedure_name,
+ r_handle,
+ true);
+
+ return result;
}
diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h
index 29c6201641..e44cc55a79 100644
--- a/modules/gdnative/gdnative.h
+++ b/modules/gdnative/gdnative.h
@@ -36,7 +36,7 @@
#include "resource.h"
#include "gdnative/gdnative.h"
-#include "gdnative_api_struct.h"
+#include "gdnative_api_struct.gen.h"
class GDNativeLibrary : public Resource {
GDCLASS(GDNativeLibrary, Resource)
@@ -100,8 +100,7 @@ public:
_FORCE_INLINE_ void set_singleton_gdnative(bool p_singleton) { singleton_gdnative = p_singleton; }
};
-typedef godot_variant (*native_call_cb)(void *, godot_string *, godot_array *);
-typedef void (*native_raw_call_cb)(void *, godot_string *, void *, int, void **, void *);
+typedef godot_variant (*native_call_cb)(void *, godot_array *);
struct GDNativeCallRegistry {
static GDNativeCallRegistry *singleton;
@@ -111,17 +110,13 @@ struct GDNativeCallRegistry {
}
inline GDNativeCallRegistry()
- : native_calls(),
- native_raw_calls() {}
+ : native_calls() {}
Map<StringName, native_call_cb> native_calls;
- Map<StringName, native_raw_call_cb> native_raw_calls;
void register_native_call_type(StringName p_call_type, native_call_cb p_callback);
- void register_native_raw_call_type(StringName p_raw_call_type, native_raw_call_cb p_callback);
Vector<StringName> get_native_call_types();
- Vector<StringName> get_native_raw_call_types();
};
class GDNative : public Reference {
@@ -149,7 +144,8 @@ public:
bool terminate();
Variant call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments = Array());
- void call_native_raw(StringName p_raw_call_type, StringName p_procedure_name, void *data, int num_args, void **args, void *r_return);
+
+ Error get_symbol(StringName p_procedure_name, void *&r_handle);
};
#endif // GDNATIVE_H
diff --git a/modules/gdnative/gdnative/basis.cpp b/modules/gdnative/gdnative/basis.cpp
index b1327cdaef..28af93f942 100644
--- a/modules/gdnative/gdnative/basis.cpp
+++ b/modules/gdnative/gdnative/basis.cpp
@@ -172,7 +172,7 @@ void GDAPI godot_basis_new_with_euler_quat(godot_basis *r_dest, const godot_quat
}
// p_elements is a pointer to an array of 3 (!!) vector3
-void GDAPI godot_basis_get_elements(godot_basis *p_self, godot_vector3 *p_elements) {
+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];
diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp
index cf1f6a4f16..64a7c33cf8 100644
--- a/modules/gdnative/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative/gdnative.cpp
@@ -41,6 +41,7 @@ extern "C" {
#endif
extern "C" void _string_api_anchor();
+extern "C" void _string_name_api_anchor();
extern "C" void _vector2_api_anchor();
extern "C" void _rect2_api_anchor();
extern "C" void _vector3_api_anchor();
@@ -61,6 +62,7 @@ extern "C" void _variant_api_anchor();
void _api_anchor() {
_string_api_anchor();
+ _string_name_api_anchor();
_vector2_api_anchor();
_rect2_api_anchor();
_vector3_api_anchor();
diff --git a/modules/gdnative/gdnative/pool_arrays.cpp b/modules/gdnative/gdnative/pool_arrays.cpp
index 1393374da2..731e930908 100644
--- a/modules/gdnative/gdnative/pool_arrays.cpp
+++ b/modules/gdnative/gdnative/pool_arrays.cpp
@@ -106,6 +106,16 @@ void GDAPI godot_pool_byte_array_resize(godot_pool_byte_array *p_self, const god
self->resize(p_size);
}
+godot_pool_byte_array_read_access GDAPI *godot_pool_byte_array_read(const godot_pool_byte_array *p_self) {
+ const PoolVector<uint8_t> *self = (const PoolVector<uint8_t> *)p_self;
+ return (godot_pool_byte_array_read_access *)memnew(PoolVector<uint8_t>::Read(self->read()));
+}
+
+godot_pool_byte_array_write_access GDAPI *godot_pool_byte_array_write(godot_pool_byte_array *p_self) {
+ PoolVector<uint8_t> *self = (PoolVector<uint8_t> *)p_self;
+ return (godot_pool_byte_array_write_access *)memnew(PoolVector<uint8_t>::Write(self->write()));
+}
+
void GDAPI godot_pool_byte_array_set(godot_pool_byte_array *p_self, const godot_int p_idx, const uint8_t p_data) {
PoolVector<uint8_t> *self = (PoolVector<uint8_t> *)p_self;
self->set(p_idx, p_data);
@@ -185,6 +195,16 @@ void GDAPI godot_pool_int_array_resize(godot_pool_int_array *p_self, const godot
self->resize(p_size);
}
+godot_pool_int_array_read_access GDAPI *godot_pool_int_array_read(const godot_pool_int_array *p_self) {
+ const PoolVector<godot_int> *self = (const PoolVector<godot_int> *)p_self;
+ return (godot_pool_int_array_read_access *)memnew(PoolVector<godot_int>::Read(self->read()));
+}
+
+godot_pool_int_array_write_access GDAPI *godot_pool_int_array_write(godot_pool_int_array *p_self) {
+ PoolVector<godot_int> *self = (PoolVector<godot_int> *)p_self;
+ return (godot_pool_int_array_write_access *)memnew(PoolVector<godot_int>::Write(self->write()));
+}
+
void GDAPI godot_pool_int_array_set(godot_pool_int_array *p_self, const godot_int p_idx, const godot_int p_data) {
PoolVector<godot_int> *self = (PoolVector<godot_int> *)p_self;
self->set(p_idx, p_data);
@@ -260,10 +280,20 @@ void GDAPI godot_pool_real_array_remove(godot_pool_real_array *p_self, const god
}
void GDAPI godot_pool_real_array_resize(godot_pool_real_array *p_self, const godot_int p_size) {
- PoolVector<godot_int> *self = (PoolVector<godot_int> *)p_self;
+ PoolVector<godot_real> *self = (PoolVector<godot_real> *)p_self;
self->resize(p_size);
}
+godot_pool_real_array_read_access GDAPI *godot_pool_real_array_read(const godot_pool_real_array *p_self) {
+ const PoolVector<godot_real> *self = (const PoolVector<godot_real> *)p_self;
+ return (godot_pool_real_array_read_access *)memnew(PoolVector<godot_real>::Read(self->read()));
+}
+
+godot_pool_int_array_write_access GDAPI *godot_pool_real_array_write(godot_pool_real_array *p_self) {
+ PoolVector<godot_real> *self = (PoolVector<godot_real> *)p_self;
+ return (godot_pool_real_array_write_access *)memnew(PoolVector<godot_real>::Write(self->write()));
+}
+
void GDAPI godot_pool_real_array_set(godot_pool_real_array *p_self, const godot_int p_idx, const godot_real p_data) {
PoolVector<godot_real> *self = (PoolVector<godot_real> *)p_self;
self->set(p_idx, p_data);
@@ -346,6 +376,16 @@ void GDAPI godot_pool_string_array_resize(godot_pool_string_array *p_self, const
self->resize(p_size);
}
+godot_pool_string_array_read_access GDAPI *godot_pool_string_array_read(const godot_pool_string_array *p_self) {
+ const PoolVector<String> *self = (const PoolVector<String> *)p_self;
+ return (godot_pool_string_array_read_access *)memnew(PoolVector<String>::Read(self->read()));
+}
+
+godot_pool_string_array_write_access GDAPI *godot_pool_string_array_write(godot_pool_string_array *p_self) {
+ PoolVector<String> *self = (PoolVector<String> *)p_self;
+ return (godot_pool_string_array_write_access *)memnew(PoolVector<String>::Write(self->write()));
+}
+
void GDAPI godot_pool_string_array_set(godot_pool_string_array *p_self, const godot_int p_idx, const godot_string *p_data) {
PoolVector<String> *self = (PoolVector<String> *)p_self;
String &s = *(String *)p_data;
@@ -433,6 +473,16 @@ void GDAPI godot_pool_vector2_array_resize(godot_pool_vector2_array *p_self, con
self->resize(p_size);
}
+godot_pool_vector2_array_read_access GDAPI *godot_pool_vector2_array_read(const godot_pool_vector2_array *p_self) {
+ const PoolVector<Vector2> *self = (const PoolVector<Vector2> *)p_self;
+ return (godot_pool_vector2_array_read_access *)memnew(PoolVector<Vector2>::Read(self->read()));
+}
+
+godot_pool_vector2_array_write_access GDAPI *godot_pool_vector2_array_write(godot_pool_vector2_array *p_self) {
+ PoolVector<Vector2> *self = (PoolVector<Vector2> *)p_self;
+ return (godot_pool_vector2_array_write_access *)memnew(PoolVector<Vector2>::Write(self->write()));
+}
+
void GDAPI godot_pool_vector2_array_set(godot_pool_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data) {
PoolVector<Vector2> *self = (PoolVector<Vector2> *)p_self;
Vector2 &s = *(Vector2 *)p_data;
@@ -519,6 +569,16 @@ void GDAPI godot_pool_vector3_array_resize(godot_pool_vector3_array *p_self, con
self->resize(p_size);
}
+godot_pool_vector3_array_read_access GDAPI *godot_pool_vector3_array_read(const godot_pool_vector3_array *p_self) {
+ const PoolVector<Vector3> *self = (const PoolVector<Vector3> *)p_self;
+ return (godot_pool_vector3_array_read_access *)memnew(PoolVector<Vector3>::Read(self->read()));
+}
+
+godot_pool_vector3_array_write_access GDAPI *godot_pool_vector3_array_write(godot_pool_vector3_array *p_self) {
+ PoolVector<Vector3> *self = (PoolVector<Vector3> *)p_self;
+ return (godot_pool_vector3_array_write_access *)memnew(PoolVector<Vector3>::Write(self->write()));
+}
+
void GDAPI godot_pool_vector3_array_set(godot_pool_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data) {
PoolVector<Vector3> *self = (PoolVector<Vector3> *)p_self;
Vector3 &s = *(Vector3 *)p_data;
@@ -605,6 +665,16 @@ void GDAPI godot_pool_color_array_resize(godot_pool_color_array *p_self, const g
self->resize(p_size);
}
+godot_pool_color_array_read_access GDAPI *godot_pool_color_array_read(const godot_pool_color_array *p_self) {
+ const PoolVector<Color> *self = (const PoolVector<Color> *)p_self;
+ return (godot_pool_color_array_read_access *)memnew(PoolVector<Color>::Read(self->read()));
+}
+
+godot_pool_color_array_write_access GDAPI *godot_pool_color_array_write(godot_pool_color_array *p_self) {
+ PoolVector<Color> *self = (PoolVector<Color> *)p_self;
+ return (godot_pool_color_array_write_access *)memnew(PoolVector<Color>::Write(self->write()));
+}
+
void GDAPI godot_pool_color_array_set(godot_pool_color_array *p_self, const godot_int p_idx, const godot_color *p_data) {
PoolVector<Color> *self = (PoolVector<Color> *)p_self;
Color &s = *(Color *)p_data;
@@ -628,6 +698,196 @@ void GDAPI godot_pool_color_array_destroy(godot_pool_color_array *p_self) {
((PoolVector<Color> *)p_self)->~PoolVector();
}
+//
+// read accessor functions
+//
+
+const uint8_t GDAPI *godot_pool_byte_array_read_access_ptr(const godot_pool_byte_array_read_access *p_read) {
+ const PoolVector<uint8_t>::Read *read = (const PoolVector<uint8_t>::Read *)p_read;
+ return read->ptr();
+}
+void GDAPI godot_pool_byte_array_read_access_operator_assign(godot_pool_byte_array_read_access *p_read, godot_pool_byte_array_read_access *p_other) {
+ PoolVector<uint8_t>::Read *read = (PoolVector<uint8_t>::Read *)p_read;
+ PoolVector<uint8_t>::Read *other = (PoolVector<uint8_t>::Read *)p_other;
+ read->operator=(*other);
+}
+void GDAPI godot_pool_byte_array_read_access_destroy(godot_pool_byte_array_read_access *p_read) {
+ memdelete((PoolVector<uint8_t>::Read *)p_read);
+}
+
+const godot_int GDAPI *godot_pool_int_array_read_access_ptr(const godot_pool_int_array_read_access *p_read) {
+ const PoolVector<godot_int>::Read *read = (const PoolVector<godot_int>::Read *)p_read;
+ return read->ptr();
+}
+void GDAPI godot_pool_int_array_read_access_operator_assign(godot_pool_int_array_read_access *p_read, godot_pool_int_array_read_access *p_other) {
+ PoolVector<godot_int>::Read *read = (PoolVector<godot_int>::Read *)p_read;
+ PoolVector<godot_int>::Read *other = (PoolVector<godot_int>::Read *)p_other;
+ read->operator=(*other);
+}
+void GDAPI godot_pool_int_array_read_access_destroy(godot_pool_int_array_read_access *p_read) {
+ memdelete((PoolVector<godot_int>::Read *)p_read);
+}
+
+const godot_real GDAPI *godot_pool_real_array_read_access_ptr(const godot_pool_real_array_read_access *p_read) {
+ const PoolVector<godot_real>::Read *read = (const PoolVector<godot_real>::Read *)p_read;
+ return read->ptr();
+}
+void GDAPI godot_pool_real_array_read_access_operator_assign(godot_pool_real_array_read_access *p_read, godot_pool_real_array_read_access *p_other) {
+ PoolVector<godot_real>::Read *read = (PoolVector<godot_real>::Read *)p_read;
+ PoolVector<godot_real>::Read *other = (PoolVector<godot_real>::Read *)p_other;
+ read->operator=(*other);
+}
+void GDAPI godot_pool_real_array_read_access_destroy(godot_pool_real_array_read_access *p_read) {
+ memdelete((PoolVector<godot_real>::Read *)p_read);
+}
+
+const godot_string GDAPI *godot_pool_string_array_read_access_ptr(const godot_pool_string_array_read_access *p_read) {
+ const PoolVector<String>::Read *read = (const PoolVector<String>::Read *)p_read;
+ return (const godot_string *)read->ptr();
+}
+void GDAPI godot_pool_string_array_read_access_operator_assign(godot_pool_string_array_read_access *p_read, godot_pool_string_array_read_access *p_other) {
+ PoolVector<String>::Read *read = (PoolVector<String>::Read *)p_read;
+ PoolVector<String>::Read *other = (PoolVector<String>::Read *)p_other;
+ read->operator=(*other);
+}
+void GDAPI godot_pool_string_array_read_access_destroy(godot_pool_string_array_read_access *p_read) {
+ memdelete((PoolVector<String>::Read *)p_read);
+}
+
+const godot_vector2 GDAPI *godot_pool_vector2_array_read_access_ptr(const godot_pool_vector2_array_read_access *p_read) {
+ const PoolVector<Vector2>::Read *read = (const PoolVector<Vector2>::Read *)p_read;
+ return (const godot_vector2 *)read->ptr();
+}
+void GDAPI godot_pool_vector2_array_read_access_operator_assign(godot_pool_vector2_array_read_access *p_read, godot_pool_vector2_array_read_access *p_other) {
+ PoolVector<Vector2>::Read *read = (PoolVector<Vector2>::Read *)p_read;
+ PoolVector<Vector2>::Read *other = (PoolVector<Vector2>::Read *)p_other;
+ read->operator=(*other);
+}
+void GDAPI godot_pool_vector2_array_read_access_destroy(godot_pool_vector2_array_read_access *p_read) {
+ memdelete((PoolVector<Vector2>::Read *)p_read);
+}
+
+const godot_vector3 GDAPI *godot_pool_vector3_array_read_access_ptr(const godot_pool_vector3_array_read_access *p_read) {
+ const PoolVector<Vector3>::Read *read = (const PoolVector<Vector3>::Read *)p_read;
+ return (const godot_vector3 *)read->ptr();
+}
+void GDAPI godot_pool_vector3_array_read_access_operator_assign(godot_pool_vector3_array_read_access *p_read, godot_pool_vector3_array_read_access *p_other) {
+ PoolVector<Vector3>::Read *read = (PoolVector<Vector3>::Read *)p_read;
+ PoolVector<Vector3>::Read *other = (PoolVector<Vector3>::Read *)p_other;
+ read->operator=(*other);
+}
+void GDAPI godot_pool_vector3_array_read_access_destroy(godot_pool_vector3_array_read_access *p_read) {
+ memdelete((PoolVector<Vector2>::Read *)p_read);
+}
+
+const godot_color GDAPI *godot_pool_color_array_read_access_ptr(const godot_pool_color_array_read_access *p_read) {
+ const PoolVector<Color>::Read *read = (const PoolVector<Color>::Read *)p_read;
+ return (const godot_color *)read->ptr();
+}
+void GDAPI godot_pool_color_array_read_access_operator_assign(godot_pool_color_array_read_access *p_read, godot_pool_color_array_read_access *p_other) {
+ PoolVector<Color>::Read *read = (PoolVector<Color>::Read *)p_read;
+ PoolVector<Color>::Read *other = (PoolVector<Color>::Read *)p_other;
+ read->operator=(*other);
+}
+void GDAPI godot_pool_color_array_read_access_destroy(godot_pool_color_array_read_access *p_read) {
+ memdelete((PoolVector<Color>::Read *)p_read);
+}
+
+//
+// write accessor functions
+//
+
+uint8_t GDAPI *godot_pool_byte_array_write_access_ptr(const godot_pool_byte_array_write_access *p_write) {
+ PoolVector<uint8_t>::Write *write = (PoolVector<uint8_t>::Write *)p_write;
+ return write->ptr();
+}
+void GDAPI godot_pool_byte_array_write_access_operator_assign(godot_pool_byte_array_write_access *p_write, godot_pool_byte_array_write_access *p_other) {
+ PoolVector<uint8_t>::Write *write = (PoolVector<uint8_t>::Write *)p_write;
+ PoolVector<uint8_t>::Write *other = (PoolVector<uint8_t>::Write *)p_other;
+ write->operator=(*other);
+}
+void GDAPI godot_pool_byte_array_write_access_destroy(godot_pool_byte_array_write_access *p_write) {
+ memdelete((PoolVector<uint8_t>::Write *)p_write);
+}
+
+godot_int GDAPI *godot_pool_int_array_write_access_ptr(const godot_pool_int_array_write_access *p_write) {
+ PoolVector<godot_int>::Write *write = (PoolVector<godot_int>::Write *)p_write;
+ return write->ptr();
+}
+void GDAPI godot_pool_int_array_write_access_operator_assign(godot_pool_int_array_write_access *p_write, godot_pool_int_array_write_access *p_other) {
+ PoolVector<godot_int>::Write *write = (PoolVector<godot_int>::Write *)p_write;
+ PoolVector<godot_int>::Write *other = (PoolVector<godot_int>::Write *)p_other;
+ write->operator=(*other);
+}
+void GDAPI godot_pool_int_array_write_access_destroy(godot_pool_int_array_write_access *p_write) {
+ memdelete((PoolVector<godot_int>::Write *)p_write);
+}
+
+godot_real GDAPI *godot_pool_real_array_write_access_ptr(const godot_pool_real_array_write_access *p_write) {
+ PoolVector<godot_real>::Write *write = (PoolVector<godot_real>::Write *)p_write;
+ return write->ptr();
+}
+void GDAPI godot_pool_real_array_write_access_operator_assign(godot_pool_real_array_write_access *p_write, godot_pool_real_array_write_access *p_other) {
+ PoolVector<godot_real>::Write *write = (PoolVector<godot_real>::Write *)p_write;
+ PoolVector<godot_real>::Write *other = (PoolVector<godot_real>::Write *)p_other;
+ write->operator=(*other);
+}
+void GDAPI godot_pool_real_array_write_access_destroy(godot_pool_real_array_write_access *p_write) {
+ memdelete((PoolVector<godot_real>::Write *)p_write);
+}
+
+godot_string GDAPI *godot_pool_string_array_write_access_ptr(const godot_pool_string_array_write_access *p_write) {
+ PoolVector<String>::Write *write = (PoolVector<String>::Write *)p_write;
+ return (godot_string *)write->ptr();
+}
+void GDAPI godot_pool_string_array_write_access_operator_assign(godot_pool_string_array_write_access *p_write, godot_pool_string_array_write_access *p_other) {
+ PoolVector<String>::Write *write = (PoolVector<String>::Write *)p_write;
+ PoolVector<String>::Write *other = (PoolVector<String>::Write *)p_other;
+ write->operator=(*other);
+}
+void GDAPI godot_pool_string_array_write_access_destroy(godot_pool_string_array_write_access *p_write) {
+ memdelete((PoolVector<String>::Write *)p_write);
+}
+
+godot_vector2 GDAPI *godot_pool_vector2_array_write_access_ptr(const godot_pool_vector2_array_write_access *p_write) {
+ PoolVector<Vector2>::Write *write = (PoolVector<Vector2>::Write *)p_write;
+ return (godot_vector2 *)write->ptr();
+}
+void GDAPI godot_pool_vector2_array_write_access_operator_assign(godot_pool_vector2_array_write_access *p_write, godot_pool_vector2_array_write_access *p_other) {
+ PoolVector<Vector2>::Write *write = (PoolVector<Vector2>::Write *)p_write;
+ PoolVector<Vector2>::Write *other = (PoolVector<Vector2>::Write *)p_other;
+ write->operator=(*other);
+}
+void GDAPI godot_pool_vector2_array_write_access_destroy(godot_pool_vector2_array_write_access *p_write) {
+ memdelete((PoolVector<Vector2>::Write *)p_write);
+}
+
+godot_vector3 GDAPI *godot_pool_vector3_array_write_access_ptr(const godot_pool_vector3_array_write_access *p_write) {
+ PoolVector<Vector3>::Write *write = (PoolVector<Vector3>::Write *)p_write;
+ return (godot_vector3 *)write->ptr();
+}
+void GDAPI godot_pool_vector3_array_write_access_operator_assign(godot_pool_vector3_array_write_access *p_write, godot_pool_vector3_array_write_access *p_other) {
+ PoolVector<Vector3>::Write *write = (PoolVector<Vector3>::Write *)p_write;
+ PoolVector<Vector3>::Write *other = (PoolVector<Vector3>::Write *)p_other;
+ write->operator=(*other);
+}
+void GDAPI godot_pool_vector3_array_write_access_destroy(godot_pool_vector3_array_write_access *p_write) {
+ memdelete((PoolVector<Vector3>::Write *)p_write);
+}
+
+godot_color GDAPI *godot_pool_color_array_write_access_ptr(const godot_pool_color_array_write_access *p_write) {
+ PoolVector<Color>::Write *write = (PoolVector<Color>::Write *)p_write;
+ return (godot_color *)write->ptr();
+}
+void GDAPI godot_pool_color_array_write_access_operator_assign(godot_pool_color_array_write_access *p_write, godot_pool_color_array_write_access *p_other) {
+ PoolVector<Color>::Write *write = (PoolVector<Color>::Write *)p_write;
+ PoolVector<Color>::Write *other = (PoolVector<Color>::Write *)p_other;
+ write->operator=(*other);
+}
+void GDAPI godot_pool_color_array_write_access_destroy(godot_pool_color_array_write_access *p_write) {
+ memdelete((PoolVector<Color>::Write *)p_write);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 9b715ce36a..619003083d 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -29,9 +29,9 @@
/*************************************************************************/
#include "gdnative/string.h"
+#include "core/string_db.h"
+#include "core/ustring.h"
#include "core/variant.h"
-#include "string_db.h"
-#include "ustring.h"
#include <string.h>
@@ -65,11 +65,20 @@ void GDAPI godot_string_new_unicode_data(godot_string *r_dest, const wchar_t *p_
void GDAPI godot_string_get_data(const godot_string *p_self, char *p_dest, int *p_size) {
String *self = (String *)p_self;
- if (p_size != NULL) {
- *p_size = self->utf8().length();
- }
- if (p_dest != NULL) {
- memcpy(p_dest, self->utf8().get_data(), *p_size);
+
+ if (p_size) {
+ // we have a length pointer, that means we either want to know
+ // the length or want to write *p_size bytes into a buffer
+
+ CharString utf8_string = self->utf8();
+
+ int len = utf8_string.length();
+
+ if (p_dest) {
+ memcpy(p_dest, utf8_string.get_data(), *p_size);
+ } else {
+ *p_size = len;
+ }
}
}
@@ -78,6 +87,11 @@ wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int
return &(self->operator[](p_idx));
}
+wchar_t 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 char GDAPI *godot_string_c_str(const godot_string *p_self) {
const String *self = (const String *)p_self;
return self->utf8().get_data();
diff --git a/modules/gdnative/gdnative/string_name.cpp b/modules/gdnative/gdnative/string_name.cpp
new file mode 100644
index 0000000000..5c00fdfc2f
--- /dev/null
+++ b/modules/gdnative/gdnative/string_name.cpp
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* string_name.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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/string_name.h"
+
+#include "core/string_db.h"
+#include "core/ustring.h"
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _string_name_api_anchor() {
+}
+
+void GDAPI godot_string_name_new(godot_string_name *r_dest, const godot_string *p_name) {
+ StringName *dest = (StringName *)r_dest;
+ const String *name = (const String *)p_name;
+ memnew_placement(dest, StringName(*name));
+}
+
+void GDAPI godot_string_name_new_data(godot_string_name *r_dest, const char *p_name) {
+ 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();
+}
+
+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_destroy(godot_string_name *p_self) {
+ StringName *self = (StringName *)p_self;
+ self->~StringName();
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp
index 1b2aae607f..9ba4166c1d 100644
--- a/modules/gdnative/gdnative/variant.cpp
+++ b/modules/gdnative/gdnative/variant.cpp
@@ -480,10 +480,9 @@ godot_bool GDAPI godot_variant_hash_compare(const godot_variant *p_self, const g
return self->hash_compare(*other);
}
-godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self, godot_bool *r_valid) {
+godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self) {
const Variant *self = (const Variant *)p_self;
- bool &valid = *r_valid;
- return self->booleanize(valid);
+ return self->booleanize();
}
void GDAPI godot_variant_destroy(godot_variant *p_self) {
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
new file mode 100644
index 0000000000..ac0293172d
--- /dev/null
+++ b/modules/gdnative/gdnative_api.json
@@ -0,0 +1,5734 @@
+{
+ "version": "1.0.0",
+ "api": [
+ {
+ "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_gray",
+ "return_type": "godot_real",
+ "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_linear_interpolate",
+ "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_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_linear_interpolate",
+ "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_substract",
+ "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_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_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_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_substract",
+ "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_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_substract",
+ "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_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_linear_interpolate",
+ "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_substract",
+ "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_pool_byte_array_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "r_dest"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "r_dest"],
+ ["const godot_pool_byte_array *", "p_src"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_new_with_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "r_dest"],
+ ["const godot_array *", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_append",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"],
+ ["const uint8_t", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"],
+ ["const godot_pool_byte_array *", "p_array"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const uint8_t", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_invert",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"],
+ ["const uint8_t", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_remove",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_resize",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"],
+ ["const godot_int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_read",
+ "return_type": "godot_pool_byte_array_read_access *",
+ "arguments": [
+ ["const godot_pool_byte_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_write",
+ "return_type": "godot_pool_byte_array_write_access *",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_set",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const uint8_t", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_get",
+ "return_type": "uint8_t",
+ "arguments": [
+ ["const godot_pool_byte_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_byte_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "r_dest"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "r_dest"],
+ ["const godot_pool_int_array *", "p_src"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_new_with_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "r_dest"],
+ ["const godot_array *", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_append",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"],
+ ["const godot_int", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"],
+ ["const godot_pool_int_array *", "p_array"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_int", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_invert",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"],
+ ["const godot_int", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_remove",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_resize",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"],
+ ["const godot_int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_read",
+ "return_type": "godot_pool_int_array_read_access *",
+ "arguments": [
+ ["const godot_pool_int_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_write",
+ "return_type": "godot_pool_int_array_write_access *",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_set",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_int", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_get",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_int_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_int_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "r_dest"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "r_dest"],
+ ["const godot_pool_real_array *", "p_src"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_new_with_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "r_dest"],
+ ["const godot_array *", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_append",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"],
+ ["const godot_real", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"],
+ ["const godot_pool_real_array *", "p_array"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_real", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_invert",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"],
+ ["const godot_real", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_remove",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_resize",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"],
+ ["const godot_int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_read",
+ "return_type": "godot_pool_real_array_read_access *",
+ "arguments": [
+ ["const godot_pool_real_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_write",
+ "return_type": "godot_pool_real_array_write_access *",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_set",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_real", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_get",
+ "return_type": "godot_real",
+ "arguments": [
+ ["const godot_pool_real_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_real_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "r_dest"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "r_dest"],
+ ["const godot_pool_string_array *", "p_src"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_new_with_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "r_dest"],
+ ["const godot_array *", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_append",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"],
+ ["const godot_string *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"],
+ ["const godot_pool_string_array *", "p_array"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_string *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_invert",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"],
+ ["const godot_string *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_remove",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_resize",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"],
+ ["const godot_int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_read",
+ "return_type": "godot_pool_string_array_read_access *",
+ "arguments": [
+ ["const godot_pool_string_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_write",
+ "return_type": "godot_pool_string_array_write_access *",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_set",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_string *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_get",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_pool_string_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_string_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "r_dest"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "r_dest"],
+ ["const godot_pool_vector2_array *", "p_src"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_new_with_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "r_dest"],
+ ["const godot_array *", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_append",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"],
+ ["const godot_vector2 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"],
+ ["const godot_pool_vector2_array *", "p_array"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_vector2 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_invert",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"],
+ ["const godot_vector2 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_remove",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_resize",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"],
+ ["const godot_int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_read",
+ "return_type": "godot_pool_vector2_array_read_access *",
+ "arguments": [
+ ["const godot_pool_vector2_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_write",
+ "return_type": "godot_pool_vector2_array_write_access *",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_set",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_vector2 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_get",
+ "return_type": "godot_vector2",
+ "arguments": [
+ ["const godot_pool_vector2_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_vector2_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "r_dest"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "r_dest"],
+ ["const godot_pool_vector3_array *", "p_src"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_new_with_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "r_dest"],
+ ["const godot_array *", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_append",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"],
+ ["const godot_vector3 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"],
+ ["const godot_pool_vector3_array *", "p_array"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_vector3 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_invert",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"],
+ ["const godot_vector3 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_remove",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_resize",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"],
+ ["const godot_int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_read",
+ "return_type": "godot_pool_vector3_array_read_access *",
+ "arguments": [
+ ["const godot_pool_vector3_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_write",
+ "return_type": "godot_pool_vector3_array_write_access *",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_set",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_vector3 *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_get",
+ "return_type": "godot_vector3",
+ "arguments": [
+ ["const godot_pool_vector3_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_vector3_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "r_dest"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_new_copy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "r_dest"],
+ ["const godot_pool_color_array *", "p_src"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_new_with_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "r_dest"],
+ ["const godot_array *", "p_a"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_append",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"],
+ ["const godot_color *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_append_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"],
+ ["const godot_pool_color_array *", "p_array"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_insert",
+ "return_type": "godot_error",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_color *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_invert",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_push_back",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"],
+ ["const godot_color *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_remove",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_resize",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"],
+ ["const godot_int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_read",
+ "return_type": "godot_pool_color_array_read_access *",
+ "arguments": [
+ ["const godot_pool_color_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_write",
+ "return_type": "godot_pool_color_array_write_access *",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_set",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"],
+ ["const godot_int", "p_idx"],
+ ["const godot_color *", "p_data"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_get",
+ "return_type": "godot_color",
+ "arguments": [
+ ["const godot_pool_color_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_size",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_pool_color_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_read_access_ptr",
+ "return_type": "const uint8_t *",
+ "arguments": [
+ ["const godot_pool_byte_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_read_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array_read_access *", "p_read"],
+ ["godot_pool_byte_array_read_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_read_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_read_access_ptr",
+ "return_type": "const godot_int *",
+ "arguments": [
+ ["const godot_pool_int_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_read_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array_read_access *", "p_read"],
+ ["godot_pool_int_array_read_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_read_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_read_access_ptr",
+ "return_type": "const godot_real *",
+ "arguments": [
+ ["const godot_pool_real_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_read_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array_read_access *", "p_read"],
+ ["godot_pool_real_array_read_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_read_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_read_access_ptr",
+ "return_type": "const godot_string *",
+ "arguments": [
+ ["const godot_pool_string_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_read_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array_read_access *", "p_read"],
+ ["godot_pool_string_array_read_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_read_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_read_access_ptr",
+ "return_type": "const godot_vector2 *",
+ "arguments": [
+ ["const godot_pool_vector2_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_read_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array_read_access *", "p_read"],
+ ["godot_pool_vector2_array_read_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_read_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_read_access_ptr",
+ "return_type": "const godot_vector3 *",
+ "arguments": [
+ ["const godot_pool_vector3_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_read_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array_read_access *", "p_read"],
+ ["godot_pool_vector3_array_read_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_read_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_read_access_ptr",
+ "return_type": "const godot_color *",
+ "arguments": [
+ ["const godot_pool_color_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_read_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array_read_access *", "p_read"],
+ ["godot_pool_color_array_read_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_read_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array_read_access *", "p_read"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_write_access_ptr",
+ "return_type": "uint8_t *",
+ "arguments": [
+ ["const godot_pool_byte_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_write_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array_write_access *", "p_write"],
+ ["godot_pool_byte_array_write_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_byte_array_write_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_byte_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_write_access_ptr",
+ "return_type": "godot_int *",
+ "arguments": [
+ ["const godot_pool_int_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_write_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array_write_access *", "p_write"],
+ ["godot_pool_int_array_write_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_int_array_write_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_int_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_write_access_ptr",
+ "return_type": "godot_real *",
+ "arguments": [
+ ["const godot_pool_real_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_write_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array_write_access *", "p_write"],
+ ["godot_pool_real_array_write_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_real_array_write_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_real_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_write_access_ptr",
+ "return_type": "godot_string *",
+ "arguments": [
+ ["const godot_pool_string_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_write_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array_write_access *", "p_write"],
+ ["godot_pool_string_array_write_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_string_array_write_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_string_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_write_access_ptr",
+ "return_type": "godot_vector2 *",
+ "arguments": [
+ ["const godot_pool_vector2_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_write_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array_write_access *", "p_write"],
+ ["godot_pool_vector2_array_write_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector2_array_write_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector2_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_write_access_ptr",
+ "return_type": "godot_vector3 *",
+ "arguments": [
+ ["const godot_pool_vector3_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_write_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array_write_access *", "p_write"],
+ ["godot_pool_vector3_array_write_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_vector3_array_write_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_vector3_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_write_access_ptr",
+ "return_type": "godot_color *",
+ "arguments": [
+ ["const godot_pool_color_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_write_access_operator_assign",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array_write_access *", "p_write"],
+ ["godot_pool_color_array_write_access *", "p_other"]
+ ]
+ },
+ {
+ "name": "godot_pool_color_array_write_access_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_pool_color_array_write_access *", "p_write"]
+ ]
+ },
+ {
+ "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_pool_color_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "r_dest"],
+ ["const godot_pool_color_array *", "p_pca"]
+ ]
+ },
+ {
+ "name": "godot_array_new_pool_vector3_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "r_dest"],
+ ["const godot_pool_vector3_array *", "p_pv3a"]
+ ]
+ },
+ {
+ "name": "godot_array_new_pool_vector2_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "r_dest"],
+ ["const godot_pool_vector2_array *", "p_pv2a"]
+ ]
+ },
+ {
+ "name": "godot_array_new_pool_string_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "r_dest"],
+ ["const godot_pool_string_array *", "p_psa"]
+ ]
+ },
+ {
+ "name": "godot_array_new_pool_real_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "r_dest"],
+ ["const godot_pool_real_array *", "p_pra"]
+ ]
+ },
+ {
+ "name": "godot_array_new_pool_int_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "r_dest"],
+ ["const godot_pool_int_array *", "p_pia"]
+ ]
+ },
+ {
+ "name": "godot_array_new_pool_byte_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "r_dest"],
+ ["const godot_pool_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_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_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_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_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_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_array *", "p_self"]
+ ]
+ },
+ {
+ "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_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_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_property",
+ "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_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_get_any_point",
+ "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_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_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_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_rect3_new",
+ "return_type": "void",
+ "arguments": [
+ ["godot_rect3 *", "r_dest"],
+ ["const godot_vector3 *", "p_pos"],
+ ["const godot_vector3 *", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_position",
+ "return_type": "godot_vector3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_set_position",
+ "return_type": "void",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_vector3 *", "p_v"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_size",
+ "return_type": "godot_vector3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_set_size",
+ "return_type": "void",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_vector3 *", "p_v"]
+ ]
+ },
+ {
+ "name": "godot_rect3_as_string",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_area",
+ "return_type": "godot_real",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_has_no_area",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_has_no_surface",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_intersects",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_rect3 *", "p_with"]
+ ]
+ },
+ {
+ "name": "godot_rect3_encloses",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_rect3 *", "p_with"]
+ ]
+ },
+ {
+ "name": "godot_rect3_merge",
+ "return_type": "godot_rect3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_rect3 *", "p_with"]
+ ]
+ },
+ {
+ "name": "godot_rect3_intersection",
+ "return_type": "godot_rect3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_rect3 *", "p_with"]
+ ]
+ },
+ {
+ "name": "godot_rect3_intersects_plane",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_plane *", "p_plane"]
+ ]
+ },
+ {
+ "name": "godot_rect3_intersects_segment",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_vector3 *", "p_from"],
+ ["const godot_vector3 *", "p_to"]
+ ]
+ },
+ {
+ "name": "godot_rect3_has_point",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_vector3 *", "p_point"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_support",
+ "return_type": "godot_vector3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_vector3 *", "p_dir"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_longest_axis",
+ "return_type": "godot_vector3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_longest_axis_index",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_longest_axis_size",
+ "return_type": "godot_real",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_shortest_axis",
+ "return_type": "godot_vector3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_shortest_axis_index",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_shortest_axis_size",
+ "return_type": "godot_real",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_rect3_expand",
+ "return_type": "godot_rect3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_vector3 *", "p_to_point"]
+ ]
+ },
+ {
+ "name": "godot_rect3_grow",
+ "return_type": "godot_rect3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_real", "p_by"]
+ ]
+ },
+ {
+ "name": "godot_rect3_get_endpoint",
+ "return_type": "godot_vector3",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_rect3_operator_equal",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_rect3 *", "p_self"],
+ ["const godot_rect3 *", "p_b"]
+ ]
+ },
+ {
+ "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_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",
+ "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"],
+ ["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"],
+ ["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_rect3",
+ "return_type": "godot_rect3",
+ "arguments": [
+ ["const godot_transform *", "p_self"],
+ ["const godot_rect3 *", "p_v"]
+ ]
+ },
+ {
+ "name": "godot_transform_xform_inv_rect3",
+ "return_type": "godot_rect3",
+ "arguments": [
+ ["const godot_transform *", "p_self"],
+ ["const godot_rect3 *", "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 *", "p_v"],
+ ["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_vector2",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_vector2 *", "p_v2"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_rect2",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_rect2 *", "p_rect2"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_vector3",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_vector3 *", "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_rect3",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_rect3 *", "p_rect3"]
+ ]
+ },
+ {
+ "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_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_pool_byte_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_pool_byte_array *", "p_pba"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_pool_int_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_pool_int_array *", "p_pia"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_pool_real_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_pool_real_array *", "p_pra"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_pool_string_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_pool_string_array *", "p_psa"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_pool_vector2_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_pool_vector2_array *", "p_pv2a"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_pool_vector3_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_pool_vector3_array *", "p_pv3a"]
+ ]
+ },
+ {
+ "name": "godot_variant_new_pool_color_array",
+ "return_type": "void",
+ "arguments": [
+ ["godot_variant *", "r_dest"],
+ ["const godot_pool_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_vector2",
+ "return_type": "godot_vector2",
+ "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_vector3",
+ "return_type": "godot_vector3",
+ "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_rect3",
+ "return_type": "godot_rect3",
+ "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_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_pool_byte_array",
+ "return_type": "godot_pool_byte_array",
+ "arguments": [
+ ["const godot_variant *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_variant_as_pool_int_array",
+ "return_type": "godot_pool_int_array",
+ "arguments": [
+ ["const godot_variant *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_variant_as_pool_real_array",
+ "return_type": "godot_pool_real_array",
+ "arguments": [
+ ["const godot_variant *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_variant_as_pool_string_array",
+ "return_type": "godot_pool_string_array",
+ "arguments": [
+ ["const godot_variant *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_variant_as_pool_vector2_array",
+ "return_type": "godot_pool_vector2_array",
+ "arguments": [
+ ["const godot_variant *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_variant_as_pool_vector3_array",
+ "return_type": "godot_pool_vector3_array",
+ "arguments": [
+ ["const godot_variant *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_variant_as_pool_color_array",
+ "return_type": "godot_pool_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_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_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_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_data",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char *", "p_contents"],
+ ["const int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_string_new_unicode_data",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const wchar_t *", "p_contents"],
+ ["const int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_string_get_data",
+ "return_type": "void",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["char *", "p_dest"],
+ ["int *", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_string_operator_index",
+ "return_type": "wchar_t *",
+ "arguments": [
+ ["godot_string *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_string_operator_index_const",
+ "return_type": "wchar_t",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
+ "name": "godot_string_c_str",
+ "return_type": "const char *",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_unicode_str",
+ "return_type": "const wchar_t *",
+ "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_length",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "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_array",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_chr",
+ "return_type": "godot_string",
+ "arguments": [
+ ["wchar_t", "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_find",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_what"]
+ ]
+ },
+ {
+ "name": "godot_string_find_from",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_what"],
+ ["godot_int", "p_from"]
+ ]
+ },
+ {
+ "name": "godot_string_findmk",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_array *", "p_keys"]
+ ]
+ },
+ {
+ "name": "godot_string_findmk_from",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_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_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"],
+ ["godot_string", "p_what"]
+ ]
+ },
+ {
+ "name": "godot_string_findn_from",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_what"],
+ ["godot_int", "p_from"]
+ ]
+ },
+ {
+ "name": "godot_string_find_last",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_what"]
+ ]
+ },
+ {
+ "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_hex_to_int",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_hex_to_int_without_prefix",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_insert",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_int", "p_at_pos"],
+ ["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"],
+ ["godot_string", "p_key"],
+ ["godot_string", "p_with"]
+ ]
+ },
+ {
+ "name": "godot_string_replace",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_key"],
+ ["godot_string", "p_with"]
+ ]
+ },
+ {
+ "name": "godot_string_replacen",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_key"],
+ ["godot_string", "p_with"]
+ ]
+ },
+ {
+ "name": "godot_string_rfind",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_what"]
+ ]
+ },
+ {
+ "name": "godot_string_rfindn",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_what"]
+ ]
+ },
+ {
+ "name": "godot_string_rfind_from",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_what"],
+ ["godot_int", "p_from"]
+ ]
+ },
+ {
+ "name": "godot_string_rfindn_from",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["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_double",
+ "return_type": "double",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_to_float",
+ "return_type": "godot_real",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_to_int",
+ "return_type": "godot_int",
+ "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_double",
+ "return_type": "double",
+ "arguments": [
+ ["const char *", "p_what"]
+ ]
+ },
+ {
+ "name": "godot_string_char_to_int",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const char *", "p_what"]
+ ]
+ },
+ {
+ "name": "godot_string_wchar_to_int",
+ "return_type": "int64_t",
+ "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_char_to_int64_with_len",
+ "return_type": "int64_t",
+ "arguments": [
+ ["const wchar_t *", "p_str"],
+ ["int", "p_len"]
+ ]
+ },
+ {
+ "name": "godot_string_hex_to_int64",
+ "return_type": "int64_t",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_hex_to_int64_with_prefix",
+ "return_type": "int64_t",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_to_int64",
+ "return_type": "int64_t",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_unicode_char_to_double",
+ "return_type": "double",
+ "arguments": [
+ ["const wchar_t *", "p_str"],
+ ["const wchar_t **", "r_end"]
+ ]
+ },
+ {
+ "name": "godot_string_get_slice_count",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_get_slice",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_string", "p_splitter"],
+ ["godot_int", "p_slice"]
+ ]
+ },
+ {
+ "name": "godot_string_get_slicec",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["wchar_t", "p_splitter"],
+ ["godot_int", "p_slice"]
+ ]
+ },
+ {
+ "name": "godot_string_split",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_split_allow_empty",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_split_floats",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_split_floats_allows_empty",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_split_floats_mk",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_array *", "p_splitters"]
+ ]
+ },
+ {
+ "name": "godot_string_split_floats_mk_allows_empty",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_array *", "p_splitters"]
+ ]
+ },
+ {
+ "name": "godot_string_split_ints",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_split_ints_allows_empty",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_split_ints_mk",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_array *", "p_splitters"]
+ ]
+ },
+ {
+ "name": "godot_string_split_ints_mk_allows_empty",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_array *", "p_splitters"]
+ ]
+ },
+ {
+ "name": "godot_string_split_spaces",
+ "return_type": "godot_array",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_char_lowercase",
+ "return_type": "wchar_t",
+ "arguments": [
+ ["wchar_t", "p_char"]
+ ]
+ },
+ {
+ "name": "godot_string_char_uppercase",
+ "return_type": "wchar_t",
+ "arguments": [
+ ["wchar_t", "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": "wchar_t",
+ "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_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": "void",
+ "arguments": [
+ ["godot_string *", "p_self"],
+ ["char *", "result"]
+ ]
+ },
+ {
+ "name": "godot_string_ascii_extended",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "p_self"],
+ ["char *", "result"]
+ ]
+ },
+ {
+ "name": "godot_string_utf8",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "p_self"],
+ ["char *", "result"]
+ ]
+ },
+ {
+ "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_chars_to_utf8",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const char *", "p_utf8"]
+ ]
+ },
+ {
+ "name": "godot_string_chars_to_utf8_with_len",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const char *", "p_utf8"],
+ ["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_utf8_chars",
+ "return_type": "uint32_t",
+ "arguments": [
+ ["const wchar_t *", "p_str"]
+ ]
+ },
+ {
+ "name": "godot_string_hash_utf8_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_pool_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_sha256_buffer",
+ "return_type": "godot_pool_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_word_wrap",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_int", "p_chars_per_line"]
+ ]
+ },
+ {
+ "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_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_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_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"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_class",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["const char *", "p_base"],
+ ["godot_instance_create_func", "p_create_func"],
+ ["godot_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_instance_create_func", "p_create_func"],
+ ["godot_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_method_attributes", "p_attr"],
+ ["godot_instance_method", "p_method"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_register_property",
+ "return_type": "void",
+ "arguments": [
+ ["void *", "p_gdnative_handle"],
+ ["const char *", "p_name"],
+ ["const char *", "p_path"],
+ ["godot_property_attributes *", "p_attr"],
+ ["godot_property_set_func", "p_set_func"],
+ ["godot_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_signal *", "p_signal"]
+ ]
+ },
+ {
+ "name": "godot_nativescript_get_userdata",
+ "return_type": "void *",
+ "arguments": [
+ ["godot_object *", "p_instance"]
+ ]
+ },
+ {
+ "name": "godot_arvr_register_interface",
+ "return_type": "void",
+ "arguments": [
+ ["const godot_arvr_interface_gdnative *", "p_interface"]
+ ]
+ },
+ {
+ "name": "godot_arvr_get_worldscale",
+ "return_type": "godot_real",
+ "arguments": []
+ },
+ {
+ "name": "godot_arvr_get_reference_frame",
+ "return_type": "godot_transform",
+ "arguments": []
+ },
+ {
+ "name": "godot_arvr_blit",
+ "return_type": "void",
+ "arguments": [
+ ["int", "p_eye"],
+ ["godot_rid *", "p_render_target"],
+ ["godot_rect2 *", "p_screen_rect"]
+ ]
+ },
+ {
+ "name": "godot_arvr_get_texid",
+ "return_type": "godot_int",
+ "arguments": [
+ ["godot_rid *", "p_render_target"]
+ ]
+ },
+ {
+ "name": "godot_arvr_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_arvr_remove_controller",
+ "return_type": "void",
+ "arguments": [
+ ["godot_int", "p_controller_id"]
+ ]
+ },
+ {
+ "name": "godot_arvr_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_arvr_set_controller_button",
+ "return_type": "void",
+ "arguments": [
+ ["godot_int", "p_controller_id"],
+ ["godot_int", "p_button"],
+ ["godot_bool", "p_is_pressed"]
+ ]
+ },
+ {
+ "name": "godot_arvr_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_arvr_get_controller_rumble",
+ "return_type": "godot_real",
+ "arguments": [
+ ["godot_int", "p_controller_id"]
+ ]
+ }
+ ]
+}
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index edab028cba..d0639589b7 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -46,11 +46,20 @@ typedef struct {
} godot_array;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/pool_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_pool_color_array(godot_array *r_dest, const godot_pool_color_array *p_pca);
diff --git a/modules/gdnative/include/gdnative/basis.h b/modules/gdnative/include/gdnative/basis.h
index 8ff6a6f541..49ca765a01 100644
--- a/modules/gdnative/include/gdnative/basis.h
+++ b/modules/gdnative/include/gdnative/basis.h
@@ -45,10 +45,19 @@ 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);
@@ -88,7 +97,7 @@ void GDAPI godot_basis_new(godot_basis *r_dest);
void GDAPI godot_basis_new_with_euler_quat(godot_basis *r_dest, const godot_quat *p_euler);
// p_elements is a pointer to an array of 3 (!!) vector3
-void GDAPI godot_basis_get_elements(godot_basis *p_self, godot_vector3 *p_elements);
+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);
diff --git a/modules/gdnative/include/gdnative/color.h b/modules/gdnative/include/gdnative/color.h
index 14265466b9..857e86a738 100644
--- a/modules/gdnative/include/gdnative/color.h
+++ b/modules/gdnative/include/gdnative/color.h
@@ -45,9 +45,18 @@ 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);
diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h
index c85c3f3830..e68d0fdc29 100644
--- a/modules/gdnative/include/gdnative/dictionary.h
+++ b/modules/gdnative/include/gdnative/dictionary.h
@@ -45,10 +45,19 @@ 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_destroy(godot_dictionary *p_self);
diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h
index 04dca6f56d..25d45db306 100644
--- a/modules/gdnative/include/gdnative/gdnative.h
+++ b/modules/gdnative/include/gdnative/gdnative.h
@@ -34,29 +34,20 @@
extern "C" {
#endif
-#ifdef GDAPI_BUILT_IN
-#define GDAPI_EXPORT
-#endif
-
#ifdef _WIN32
-#if defined(GDAPI_EXPORT)
-#define GDCALLINGCONV
-#define GDAPI __declspec(dllexport) GDCALLINGCONV
-#else
#define GDCALLINGCONV
-#define GDAPI __declspec(dllimport) GDCALLINGCONV
-#endif
+#define GDAPI GDCALLINGCONV
#elif defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE
-#define GDCALLINGCONV
-#define GDAPI
+#define GDCALLINGCONV __attribute__((visibility("default")))
+#define GDAPI GDCALLINGCONV
#elif TARGET_OS_MAC
#define GDCALLINGCONV __attribute__((sysv_abi))
#define GDAPI GDCALLINGCONV
#endif
#else
-#define GDCALLINGCONV __attribute__((sysv_abi, visibility("default")))
+#define GDCALLINGCONV __attribute__((sysv_abi))
#define GDAPI GDCALLINGCONV
#endif
@@ -103,7 +94,7 @@ typedef enum {
GODOT_ERR_CANT_CONNECT, // (25)
GODOT_ERR_CANT_RESOLVE,
GODOT_ERR_CONNECTION_ERROR,
- GODOT_ERR_CANT_AQUIRE_RESOURCE,
+ GODOT_ERR_CANT_ACQUIRE_RESOURCE,
GODOT_ERR_CANT_FORK,
GODOT_ERR_INVALID_DATA, ///< Data passed is invalid (30)
GODOT_ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
@@ -150,6 +141,10 @@ typedef void godot_object;
#include <gdnative/string.h>
+/////// String name
+
+#include <gdnative/string_name.h>
+
////// Vector2
#include <gdnative/vector2.h>
@@ -237,12 +232,13 @@ godot_variant GDAPI godot_method_bind_call(godot_method_bind *p_method_bind, god
struct godot_gdnative_api_struct; // Forward declaration
typedef struct {
- const struct godot_gdnative_api_struct *api_struct;
godot_bool in_editor;
uint64_t core_api_hash;
uint64_t editor_api_hash;
uint64_t no_api_hash;
godot_object *gd_native_library; // pointer to GDNativeLibrary that is being initialized
+ const struct godot_gdnative_api_struct *api_struct;
+ const godot_string *active_library_path;
} godot_gdnative_init_options;
typedef struct {
@@ -259,7 +255,7 @@ godot_dictionary GDAPI godot_get_global_constants();
////// GDNative procedure types
typedef void (*godot_gdnative_init_fn)(godot_gdnative_init_options *);
typedef void (*godot_gdnative_terminate_fn)(godot_gdnative_terminate_options *);
-typedef godot_variant (*godot_gdnative_procedure_fn)(void *, godot_array *);
+typedef godot_variant (*godot_gdnative_procedure_fn)(godot_array *);
////// System Functions
diff --git a/modules/gdnative/include/gdnative/node_path.h b/modules/gdnative/include/gdnative/node_path.h
index 0cfdbc1127..42446175d8 100644
--- a/modules/gdnative/include/gdnative/node_path.h
+++ b/modules/gdnative/include/gdnative/node_path.h
@@ -45,9 +45,18 @@ 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_destroy(godot_node_path *p_self);
diff --git a/modules/gdnative/include/gdnative/plane.h b/modules/gdnative/include/gdnative/plane.h
index 6a8915e08b..dddd172122 100644
--- a/modules/gdnative/include/gdnative/plane.h
+++ b/modules/gdnative/include/gdnative/plane.h
@@ -45,9 +45,18 @@ 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);
diff --git a/modules/gdnative/include/gdnative/pool_arrays.h b/modules/gdnative/include/gdnative/pool_arrays.h
index cb1095ee8c..81500c9186 100644
--- a/modules/gdnative/include/gdnative/pool_arrays.h
+++ b/modules/gdnative/include/gdnative/pool_arrays.h
@@ -36,6 +36,38 @@ extern "C" {
#include <stdint.h>
+/////// Read Access
+
+#define GODOT_POOL_ARRAY_READ_ACCESS_SIZE 1
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_POOL_ARRAY_READ_ACCESS_SIZE];
+} godot_pool_array_read_access;
+
+typedef godot_pool_array_read_access godot_pool_byte_array_read_access;
+typedef godot_pool_array_read_access godot_pool_int_array_read_access;
+typedef godot_pool_array_read_access godot_pool_real_array_read_access;
+typedef godot_pool_array_read_access godot_pool_string_array_read_access;
+typedef godot_pool_array_read_access godot_pool_vector2_array_read_access;
+typedef godot_pool_array_read_access godot_pool_vector3_array_read_access;
+typedef godot_pool_array_read_access godot_pool_color_array_read_access;
+
+/////// Write Access
+
+#define GODOT_POOL_ARRAY_WRITE_ACCESS_SIZE 1
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_POOL_ARRAY_WRITE_ACCESS_SIZE];
+} godot_pool_array_write_access;
+
+typedef godot_pool_array_write_access godot_pool_byte_array_write_access;
+typedef godot_pool_array_write_access godot_pool_int_array_write_access;
+typedef godot_pool_array_write_access godot_pool_real_array_write_access;
+typedef godot_pool_array_write_access godot_pool_string_array_write_access;
+typedef godot_pool_array_write_access godot_pool_vector2_array_write_access;
+typedef godot_pool_array_write_access godot_pool_vector3_array_write_access;
+typedef godot_pool_array_write_access godot_pool_color_array_write_access;
+
/////// PoolByteArray
#define GODOT_POOL_BYTE_ARRAY_SIZE sizeof(void *)
@@ -113,6 +145,11 @@ typedef struct {
} godot_pool_color_array;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/array.h>
#include <gdnative/color.h>
#include <gdnative/vector2.h>
@@ -120,6 +157,10 @@ typedef struct {
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// byte
void GDAPI godot_pool_byte_array_new(godot_pool_byte_array *r_dest);
@@ -140,6 +181,10 @@ void GDAPI godot_pool_byte_array_remove(godot_pool_byte_array *p_self, const god
void GDAPI godot_pool_byte_array_resize(godot_pool_byte_array *p_self, const godot_int p_size);
+godot_pool_byte_array_read_access GDAPI *godot_pool_byte_array_read(const godot_pool_byte_array *p_self);
+
+godot_pool_byte_array_write_access GDAPI *godot_pool_byte_array_write(godot_pool_byte_array *p_self);
+
void GDAPI godot_pool_byte_array_set(godot_pool_byte_array *p_self, const godot_int p_idx, const uint8_t p_data);
uint8_t GDAPI godot_pool_byte_array_get(const godot_pool_byte_array *p_self, const godot_int p_idx);
@@ -167,6 +212,10 @@ void GDAPI godot_pool_int_array_remove(godot_pool_int_array *p_self, const godot
void GDAPI godot_pool_int_array_resize(godot_pool_int_array *p_self, const godot_int p_size);
+godot_pool_int_array_read_access GDAPI *godot_pool_int_array_read(const godot_pool_int_array *p_self);
+
+godot_pool_int_array_write_access GDAPI *godot_pool_int_array_write(godot_pool_int_array *p_self);
+
void GDAPI godot_pool_int_array_set(godot_pool_int_array *p_self, const godot_int p_idx, const godot_int p_data);
godot_int GDAPI godot_pool_int_array_get(const godot_pool_int_array *p_self, const godot_int p_idx);
@@ -194,6 +243,10 @@ void GDAPI godot_pool_real_array_remove(godot_pool_real_array *p_self, const god
void GDAPI godot_pool_real_array_resize(godot_pool_real_array *p_self, const godot_int p_size);
+godot_pool_real_array_read_access GDAPI *godot_pool_real_array_read(const godot_pool_real_array *p_self);
+
+godot_pool_real_array_write_access GDAPI *godot_pool_real_array_write(godot_pool_real_array *p_self);
+
void GDAPI godot_pool_real_array_set(godot_pool_real_array *p_self, const godot_int p_idx, const godot_real p_data);
godot_real GDAPI godot_pool_real_array_get(const godot_pool_real_array *p_self, const godot_int p_idx);
@@ -221,6 +274,10 @@ void GDAPI godot_pool_string_array_remove(godot_pool_string_array *p_self, const
void GDAPI godot_pool_string_array_resize(godot_pool_string_array *p_self, const godot_int p_size);
+godot_pool_string_array_read_access GDAPI *godot_pool_string_array_read(const godot_pool_string_array *p_self);
+
+godot_pool_string_array_write_access GDAPI *godot_pool_string_array_write(godot_pool_string_array *p_self);
+
void GDAPI godot_pool_string_array_set(godot_pool_string_array *p_self, const godot_int p_idx, const godot_string *p_data);
godot_string GDAPI godot_pool_string_array_get(const godot_pool_string_array *p_self, const godot_int p_idx);
@@ -248,6 +305,10 @@ void GDAPI godot_pool_vector2_array_remove(godot_pool_vector2_array *p_self, con
void GDAPI godot_pool_vector2_array_resize(godot_pool_vector2_array *p_self, const godot_int p_size);
+godot_pool_vector2_array_read_access GDAPI *godot_pool_vector2_array_read(const godot_pool_vector2_array *p_self);
+
+godot_pool_vector2_array_write_access GDAPI *godot_pool_vector2_array_write(godot_pool_vector2_array *p_self);
+
void GDAPI godot_pool_vector2_array_set(godot_pool_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data);
godot_vector2 GDAPI godot_pool_vector2_array_get(const godot_pool_vector2_array *p_self, const godot_int p_idx);
@@ -275,6 +336,10 @@ void GDAPI godot_pool_vector3_array_remove(godot_pool_vector3_array *p_self, con
void GDAPI godot_pool_vector3_array_resize(godot_pool_vector3_array *p_self, const godot_int p_size);
+godot_pool_vector3_array_read_access GDAPI *godot_pool_vector3_array_read(const godot_pool_vector3_array *p_self);
+
+godot_pool_vector3_array_write_access GDAPI *godot_pool_vector3_array_write(godot_pool_vector3_array *p_self);
+
void GDAPI godot_pool_vector3_array_set(godot_pool_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data);
godot_vector3 GDAPI godot_pool_vector3_array_get(const godot_pool_vector3_array *p_self, const godot_int p_idx);
@@ -302,6 +367,10 @@ void GDAPI godot_pool_color_array_remove(godot_pool_color_array *p_self, const g
void GDAPI godot_pool_color_array_resize(godot_pool_color_array *p_self, const godot_int p_size);
+godot_pool_color_array_read_access GDAPI *godot_pool_color_array_read(const godot_pool_color_array *p_self);
+
+godot_pool_color_array_write_access GDAPI *godot_pool_color_array_write(godot_pool_color_array *p_self);
+
void GDAPI godot_pool_color_array_set(godot_pool_color_array *p_self, const godot_int p_idx, const godot_color *p_data);
godot_color GDAPI godot_pool_color_array_get(const godot_pool_color_array *p_self, const godot_int p_idx);
@@ -309,6 +378,70 @@ godot_int GDAPI godot_pool_color_array_size(const godot_pool_color_array *p_self
void GDAPI godot_pool_color_array_destroy(godot_pool_color_array *p_self);
+//
+// read accessor functions
+//
+
+const uint8_t GDAPI *godot_pool_byte_array_read_access_ptr(const godot_pool_byte_array_read_access *p_read);
+void GDAPI godot_pool_byte_array_read_access_operator_assign(godot_pool_byte_array_read_access *p_read, godot_pool_byte_array_read_access *p_other);
+void GDAPI godot_pool_byte_array_read_access_destroy(godot_pool_byte_array_read_access *p_read);
+
+const godot_int GDAPI *godot_pool_int_array_read_access_ptr(const godot_pool_int_array_read_access *p_read);
+void GDAPI godot_pool_int_array_read_access_operator_assign(godot_pool_int_array_read_access *p_read, godot_pool_int_array_read_access *p_other);
+void GDAPI godot_pool_int_array_read_access_destroy(godot_pool_int_array_read_access *p_read);
+
+const godot_real GDAPI *godot_pool_real_array_read_access_ptr(const godot_pool_real_array_read_access *p_read);
+void GDAPI godot_pool_real_array_read_access_operator_assign(godot_pool_real_array_read_access *p_read, godot_pool_real_array_read_access *p_other);
+void GDAPI godot_pool_real_array_read_access_destroy(godot_pool_real_array_read_access *p_read);
+
+const godot_string GDAPI *godot_pool_string_array_read_access_ptr(const godot_pool_string_array_read_access *p_read);
+void GDAPI godot_pool_string_array_read_access_operator_assign(godot_pool_string_array_read_access *p_read, godot_pool_string_array_read_access *p_other);
+void GDAPI godot_pool_string_array_read_access_destroy(godot_pool_string_array_read_access *p_read);
+
+const godot_vector2 GDAPI *godot_pool_vector2_array_read_access_ptr(const godot_pool_vector2_array_read_access *p_read);
+void GDAPI godot_pool_vector2_array_read_access_operator_assign(godot_pool_vector2_array_read_access *p_read, godot_pool_vector2_array_read_access *p_other);
+void GDAPI godot_pool_vector2_array_read_access_destroy(godot_pool_vector2_array_read_access *p_read);
+
+const godot_vector3 GDAPI *godot_pool_vector3_array_read_access_ptr(const godot_pool_vector3_array_read_access *p_read);
+void GDAPI godot_pool_vector3_array_read_access_operator_assign(godot_pool_vector3_array_read_access *p_read, godot_pool_vector3_array_read_access *p_other);
+void GDAPI godot_pool_vector3_array_read_access_destroy(godot_pool_vector3_array_read_access *p_read);
+
+const godot_color GDAPI *godot_pool_color_array_read_access_ptr(const godot_pool_color_array_read_access *p_read);
+void GDAPI godot_pool_color_array_read_access_operator_assign(godot_pool_color_array_read_access *p_read, godot_pool_color_array_read_access *p_other);
+void GDAPI godot_pool_color_array_read_access_destroy(godot_pool_color_array_read_access *p_read);
+
+//
+// write accessor functions
+//
+
+uint8_t GDAPI *godot_pool_byte_array_write_access_ptr(const godot_pool_byte_array_write_access *p_write);
+void GDAPI godot_pool_byte_array_write_access_operator_assign(godot_pool_byte_array_write_access *p_write, godot_pool_byte_array_write_access *p_other);
+void GDAPI godot_pool_byte_array_write_access_destroy(godot_pool_byte_array_write_access *p_write);
+
+godot_int GDAPI *godot_pool_int_array_write_access_ptr(const godot_pool_int_array_write_access *p_write);
+void GDAPI godot_pool_int_array_write_access_operator_assign(godot_pool_int_array_write_access *p_write, godot_pool_int_array_write_access *p_other);
+void GDAPI godot_pool_int_array_write_access_destroy(godot_pool_int_array_write_access *p_write);
+
+godot_real GDAPI *godot_pool_real_array_write_access_ptr(const godot_pool_real_array_write_access *p_write);
+void GDAPI godot_pool_real_array_write_access_operator_assign(godot_pool_real_array_write_access *p_write, godot_pool_real_array_write_access *p_other);
+void GDAPI godot_pool_real_array_write_access_destroy(godot_pool_real_array_write_access *p_write);
+
+godot_string GDAPI *godot_pool_string_array_write_access_ptr(const godot_pool_string_array_write_access *p_write);
+void GDAPI godot_pool_string_array_write_access_operator_assign(godot_pool_string_array_write_access *p_write, godot_pool_string_array_write_access *p_other);
+void GDAPI godot_pool_string_array_write_access_destroy(godot_pool_string_array_write_access *p_write);
+
+godot_vector2 GDAPI *godot_pool_vector2_array_write_access_ptr(const godot_pool_vector2_array_write_access *p_write);
+void GDAPI godot_pool_vector2_array_write_access_operator_assign(godot_pool_vector2_array_write_access *p_write, godot_pool_vector2_array_write_access *p_other);
+void GDAPI godot_pool_vector2_array_write_access_destroy(godot_pool_vector2_array_write_access *p_write);
+
+godot_vector3 GDAPI *godot_pool_vector3_array_write_access_ptr(const godot_pool_vector3_array_write_access *p_write);
+void GDAPI godot_pool_vector3_array_write_access_operator_assign(godot_pool_vector3_array_write_access *p_write, godot_pool_vector3_array_write_access *p_other);
+void GDAPI godot_pool_vector3_array_write_access_destroy(godot_pool_vector3_array_write_access *p_write);
+
+godot_color GDAPI *godot_pool_color_array_write_access_ptr(const godot_pool_color_array_write_access *p_write);
+void GDAPI godot_pool_color_array_write_access_operator_assign(godot_pool_color_array_write_access *p_write, godot_pool_color_array_write_access *p_other);
+void GDAPI godot_pool_color_array_write_access_destroy(godot_pool_color_array_write_access *p_write);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quat.h
index 4ffb96eb26..acae6e3e90 100644
--- a/modules/gdnative/include/gdnative/quat.h
+++ b/modules/gdnative/include/gdnative/quat.h
@@ -45,9 +45,18 @@ 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);
diff --git a/modules/gdnative/include/gdnative/rect2.h b/modules/gdnative/include/gdnative/rect2.h
index 9e6cf60342..1c66443d4f 100644
--- a/modules/gdnative/include/gdnative/rect2.h
+++ b/modules/gdnative/include/gdnative/rect2.h
@@ -43,9 +43,18 @@ typedef struct godot_rect2 {
} godot_rect2;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/vector2.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
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);
diff --git a/modules/gdnative/include/gdnative/rect3.h b/modules/gdnative/include/gdnative/rect3.h
index f94b6fea25..f603a9268a 100644
--- a/modules/gdnative/include/gdnative/rect3.h
+++ b/modules/gdnative/include/gdnative/rect3.h
@@ -45,10 +45,19 @@ typedef struct {
} godot_rect3;
#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_rect3_new(godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size);
godot_vector3 GDAPI godot_rect3_get_position(const godot_rect3 *p_self);
diff --git a/modules/gdnative/include/gdnative/rid.h b/modules/gdnative/include/gdnative/rid.h
index d9b5336fc9..caa1bb967e 100644
--- a/modules/gdnative/include/gdnative/rid.h
+++ b/modules/gdnative/include/gdnative/rid.h
@@ -45,8 +45,17 @@ 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);
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index aca23a81d8..29510313c9 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -46,9 +46,18 @@ typedef struct {
} godot_string;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
#include <gdnative/variant.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
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_new_data(godot_string *r_dest, const char *p_contents, const int p_size);
@@ -57,6 +66,7 @@ void GDAPI godot_string_new_unicode_data(godot_string *r_dest, const wchar_t *p_
void GDAPI godot_string_get_data(const godot_string *p_self, char *p_dest, int *p_size);
wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx);
+wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx);
const char GDAPI *godot_string_c_str(const godot_string *p_self);
const wchar_t GDAPI *godot_string_unicode_str(const godot_string *p_self);
diff --git a/modules/gdnative/include/gdnative/string_name.h b/modules/gdnative/include/gdnative/string_name.h
new file mode 100644
index 0000000000..ee9f603d20
--- /dev/null
+++ b/modules/gdnative/include/gdnative/string_name.h
@@ -0,0 +1,77 @@
+/*************************************************************************/
+/* string_name.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_STRING_NAME_H
+#define GODOT_STRING_NAME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <wchar.h>
+
+#define GODOT_STRING_NAME_SIZE sizeof(void *)
+
+#ifndef GODOT_CORE_API_GODOT_STRING_NAME_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_STRING_NAME_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_STRING_NAME_SIZE];
+} 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_destroy(godot_string_name *p_self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GODOT_STRING_NAME_H
diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform.h
index 656afae129..8f50b01fb5 100644
--- a/modules/gdnative/include/gdnative/transform.h
+++ b/modules/gdnative/include/gdnative/transform.h
@@ -45,11 +45,20 @@ 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);
diff --git a/modules/gdnative/include/gdnative/transform2d.h b/modules/gdnative/include/gdnative/transform2d.h
index a945868b17..c68bd2963f 100644
--- a/modules/gdnative/include/gdnative/transform2d.h
+++ b/modules/gdnative/include/gdnative/transform2d.h
@@ -45,10 +45,19 @@ 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);
diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h
index 969506585d..3d744ef1f2 100644
--- a/modules/gdnative/include/gdnative/variant.h
+++ b/modules/gdnative/include/gdnative/variant.h
@@ -99,6 +99,11 @@ typedef struct godot_variant_call_error {
godot_variant_type expected;
} godot_variant_call_error;
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/array.h>
#include <gdnative/basis.h>
#include <gdnative/color.h>
@@ -119,6 +124,10 @@ typedef struct godot_variant_call_error {
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
godot_variant_type GDAPI godot_variant_get_type(const godot_variant *p_v);
void GDAPI godot_variant_new_copy(godot_variant *r_dest, const godot_variant *p_src);
@@ -190,7 +199,7 @@ godot_bool GDAPI godot_variant_operator_less(const godot_variant *p_self, const
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, godot_bool *r_valid);
+godot_bool GDAPI godot_variant_booleanize(const godot_variant *p_self);
void GDAPI godot_variant_destroy(godot_variant *p_self);
diff --git a/modules/gdnative/include/gdnative/vector2.h b/modules/gdnative/include/gdnative/vector2.h
index 0af4abae27..07105abaf2 100644
--- a/modules/gdnative/include/gdnative/vector2.h
+++ b/modules/gdnative/include/gdnative/vector2.h
@@ -45,8 +45,17 @@ typedef struct {
} godot_vector2;
#endif
+// reduce extern "C" nesting for VS2013
+#ifdef __cplusplus
+}
+#endif
+
#include <gdnative/gdnative.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
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);
diff --git a/modules/gdnative/include/gdnative/vector3.h b/modules/gdnative/include/gdnative/vector3.h
index a27d516ec5..3ed23778ec 100644
--- a/modules/gdnative/include/gdnative/vector3.h
+++ b/modules/gdnative/include/gdnative/vector3.h
@@ -45,9 +45,18 @@ typedef struct {
} godot_vector3;
#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,
diff --git a/modules/gdnative/include/gdnative_api_struct.h b/modules/gdnative/include/gdnative_api_struct.h
deleted file mode 100644
index cfebeb08cc..0000000000
--- a/modules/gdnative/include/gdnative_api_struct.h
+++ /dev/null
@@ -1,723 +0,0 @@
-/*************************************************************************/
-/* gdnative_api_struct.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_API_STRUCT_H
-#define GODOT_GDNATIVE_API_STRUCT_H
-
-#include <gdnative/gdnative.h>
-#include <nativescript/godot_nativescript.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Using X_MACRO to keep api function signatures in a single list
-#define GODOT_GDNATIVE_API_FUNCTIONS \
- GDAPI_FUNC_VOID(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) \
- GDAPI_FUNC_VOID(godot_color_new_rgb, godot_color *r_dest, const godot_real p_r, const godot_real p_g, const godot_real p_b) \
- GDAPI_FUNC(godot_color_get_r, godot_real, const godot_color *p_self) \
- GDAPI_FUNC_VOID(godot_color_set_r, godot_color *p_self, const godot_real r) \
- GDAPI_FUNC(godot_color_get_g, godot_real, const godot_color *p_self) \
- GDAPI_FUNC_VOID(godot_color_set_g, godot_color *p_self, const godot_real g) \
- GDAPI_FUNC(godot_color_get_b, godot_real, const godot_color *p_self) \
- GDAPI_FUNC_VOID(godot_color_set_b, godot_color *p_self, const godot_real b) \
- GDAPI_FUNC(godot_color_get_a, godot_real, const godot_color *p_self) \
- GDAPI_FUNC_VOID(godot_color_set_a, godot_color *p_self, const godot_real a) \
- GDAPI_FUNC(godot_color_get_h, godot_real, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_get_s, godot_real, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_get_v, godot_real, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_as_string, godot_string, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_to_rgba32, godot_int, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_to_argb32, godot_int, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_gray, godot_real, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_inverted, godot_color, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_contrasted, godot_color, const godot_color *p_self) \
- GDAPI_FUNC(godot_color_linear_interpolate, godot_color, const godot_color *p_self, const godot_color *p_b, const godot_real p_t) \
- GDAPI_FUNC(godot_color_blend, godot_color, const godot_color *p_self, const godot_color *p_over) \
- GDAPI_FUNC(godot_color_to_html, godot_string, const godot_color *p_self, const godot_bool p_with_alpha) \
- GDAPI_FUNC(godot_color_operator_equal, godot_bool, const godot_color *p_self, const godot_color *p_b) \
- GDAPI_FUNC(godot_color_operator_less, godot_bool, const godot_color *p_self, const godot_color *p_b) \
- GDAPI_FUNC_VOID(godot_vector2_new, godot_vector2 *r_dest, const godot_real p_x, const godot_real p_y) \
- GDAPI_FUNC(godot_vector2_as_string, godot_string, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_normalized, godot_vector2, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_length, godot_real, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_angle, godot_real, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_length_squared, godot_real, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_is_normalized, godot_bool, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_distance_to, godot_real, const godot_vector2 *p_self, const godot_vector2 *p_to) \
- GDAPI_FUNC(godot_vector2_distance_squared_to, godot_real, const godot_vector2 *p_self, const godot_vector2 *p_to) \
- GDAPI_FUNC(godot_vector2_angle_to, godot_real, const godot_vector2 *p_self, const godot_vector2 *p_to) \
- GDAPI_FUNC(godot_vector2_angle_to_point, godot_real, const godot_vector2 *p_self, const godot_vector2 *p_to) \
- GDAPI_FUNC(godot_vector2_linear_interpolate, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_b, const godot_real p_t) \
- GDAPI_FUNC(godot_vector2_cubic_interpolate, godot_vector2, 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) \
- GDAPI_FUNC(godot_vector2_rotated, godot_vector2, const godot_vector2 *p_self, const godot_real p_phi) \
- GDAPI_FUNC(godot_vector2_tangent, godot_vector2, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_floor, godot_vector2, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_snapped, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_by) \
- GDAPI_FUNC(godot_vector2_aspect, godot_real, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_dot, godot_real, const godot_vector2 *p_self, const godot_vector2 *p_with) \
- GDAPI_FUNC(godot_vector2_slide, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_n) \
- GDAPI_FUNC(godot_vector2_bounce, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_n) \
- GDAPI_FUNC(godot_vector2_reflect, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_n) \
- GDAPI_FUNC(godot_vector2_abs, godot_vector2, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_clamped, godot_vector2, const godot_vector2 *p_self, const godot_real p_length) \
- GDAPI_FUNC(godot_vector2_operator_add, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_b) \
- GDAPI_FUNC(godot_vector2_operator_substract, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_b) \
- GDAPI_FUNC(godot_vector2_operator_multiply_vector, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_b) \
- GDAPI_FUNC(godot_vector2_operator_multiply_scalar, godot_vector2, const godot_vector2 *p_self, const godot_real p_b) \
- GDAPI_FUNC(godot_vector2_operator_divide_vector, godot_vector2, const godot_vector2 *p_self, const godot_vector2 *p_b) \
- GDAPI_FUNC(godot_vector2_operator_divide_scalar, godot_vector2, const godot_vector2 *p_self, const godot_real p_b) \
- GDAPI_FUNC(godot_vector2_operator_equal, godot_bool, const godot_vector2 *p_self, const godot_vector2 *p_b) \
- GDAPI_FUNC(godot_vector2_operator_less, godot_bool, const godot_vector2 *p_self, const godot_vector2 *p_b) \
- GDAPI_FUNC(godot_vector2_operator_neg, godot_vector2, const godot_vector2 *p_self) \
- GDAPI_FUNC_VOID(godot_vector2_set_x, godot_vector2 *p_self, const godot_real p_x) \
- GDAPI_FUNC_VOID(godot_vector2_set_y, godot_vector2 *p_self, const godot_real p_y) \
- GDAPI_FUNC(godot_vector2_get_x, godot_real, const godot_vector2 *p_self) \
- GDAPI_FUNC(godot_vector2_get_y, godot_real, const godot_vector2 *p_self) \
- GDAPI_FUNC_VOID(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) \
- GDAPI_FUNC_VOID(godot_quat_new_with_axis_angle, godot_quat *r_dest, const godot_vector3 *p_axis, const godot_real p_angle) \
- GDAPI_FUNC(godot_quat_get_x, godot_real, const godot_quat *p_self) \
- GDAPI_FUNC_VOID(godot_quat_set_x, godot_quat *p_self, const godot_real val) \
- GDAPI_FUNC(godot_quat_get_y, godot_real, const godot_quat *p_self) \
- GDAPI_FUNC_VOID(godot_quat_set_y, godot_quat *p_self, const godot_real val) \
- GDAPI_FUNC(godot_quat_get_z, godot_real, const godot_quat *p_self) \
- GDAPI_FUNC_VOID(godot_quat_set_z, godot_quat *p_self, const godot_real val) \
- GDAPI_FUNC(godot_quat_get_w, godot_real, const godot_quat *p_self) \
- GDAPI_FUNC_VOID(godot_quat_set_w, godot_quat *p_self, const godot_real val) \
- GDAPI_FUNC(godot_quat_as_string, godot_string, const godot_quat *p_self) \
- GDAPI_FUNC(godot_quat_length, godot_real, const godot_quat *p_self) \
- GDAPI_FUNC(godot_quat_length_squared, godot_real, const godot_quat *p_self) \
- GDAPI_FUNC(godot_quat_normalized, godot_quat, const godot_quat *p_self) \
- GDAPI_FUNC(godot_quat_is_normalized, godot_bool, const godot_quat *p_self) \
- GDAPI_FUNC(godot_quat_inverse, godot_quat, const godot_quat *p_self) \
- GDAPI_FUNC(godot_quat_dot, godot_real, const godot_quat *p_self, const godot_quat *p_b) \
- GDAPI_FUNC(godot_quat_xform, godot_vector3, const godot_quat *p_self, const godot_vector3 *p_v) \
- GDAPI_FUNC(godot_quat_slerp, godot_quat, const godot_quat *p_self, const godot_quat *p_b, const godot_real p_t) \
- GDAPI_FUNC(godot_quat_slerpni, godot_quat, const godot_quat *p_self, const godot_quat *p_b, const godot_real p_t) \
- GDAPI_FUNC(godot_quat_cubic_slerp, godot_quat, 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) \
- GDAPI_FUNC(godot_quat_operator_multiply, godot_quat, const godot_quat *p_self, const godot_real p_b) \
- GDAPI_FUNC(godot_quat_operator_add, godot_quat, const godot_quat *p_self, const godot_quat *p_b) \
- GDAPI_FUNC(godot_quat_operator_substract, godot_quat, const godot_quat *p_self, const godot_quat *p_b) \
- GDAPI_FUNC(godot_quat_operator_divide, godot_quat, const godot_quat *p_self, const godot_real p_b) \
- GDAPI_FUNC(godot_quat_operator_equal, godot_bool, const godot_quat *p_self, const godot_quat *p_b) \
- GDAPI_FUNC(godot_quat_operator_neg, godot_quat, const godot_quat *p_self) \
- GDAPI_FUNC_VOID(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) \
- GDAPI_FUNC_VOID(godot_basis_new_with_axis_and_angle, godot_basis *r_dest, const godot_vector3 *p_axis, const godot_real p_phi) \
- GDAPI_FUNC_VOID(godot_basis_new_with_euler, godot_basis *r_dest, const godot_vector3 *p_euler) \
- GDAPI_FUNC(godot_basis_as_string, godot_string, const godot_basis *p_self) \
- GDAPI_FUNC(godot_basis_inverse, godot_basis, const godot_basis *p_self) \
- GDAPI_FUNC(godot_basis_transposed, godot_basis, const godot_basis *p_self) \
- GDAPI_FUNC(godot_basis_orthonormalized, godot_basis, const godot_basis *p_self) \
- GDAPI_FUNC(godot_basis_determinant, godot_real, const godot_basis *p_self) \
- GDAPI_FUNC(godot_basis_rotated, godot_basis, const godot_basis *p_self, const godot_vector3 *p_axis, const godot_real p_phi) \
- GDAPI_FUNC(godot_basis_scaled, godot_basis, const godot_basis *p_self, const godot_vector3 *p_scale) \
- GDAPI_FUNC(godot_basis_get_scale, godot_vector3, const godot_basis *p_self) \
- GDAPI_FUNC(godot_basis_get_euler, godot_vector3, const godot_basis *p_self) \
- GDAPI_FUNC(godot_basis_tdotx, godot_real, const godot_basis *p_self, const godot_vector3 *p_with) \
- GDAPI_FUNC(godot_basis_tdoty, godot_real, const godot_basis *p_self, const godot_vector3 *p_with) \
- GDAPI_FUNC(godot_basis_tdotz, godot_real, const godot_basis *p_self, const godot_vector3 *p_with) \
- GDAPI_FUNC(godot_basis_xform, godot_vector3, const godot_basis *p_self, const godot_vector3 *p_v) \
- GDAPI_FUNC(godot_basis_xform_inv, godot_vector3, const godot_basis *p_self, const godot_vector3 *p_v) \
- GDAPI_FUNC(godot_basis_get_orthogonal_index, godot_int, const godot_basis *p_self) \
- GDAPI_FUNC_VOID(godot_basis_new, godot_basis *r_dest) \
- GDAPI_FUNC_VOID(godot_basis_new_with_euler_quat, godot_basis *r_dest, const godot_quat *p_euler) \
- GDAPI_FUNC_VOID(godot_basis_get_elements, godot_basis *p_self, godot_vector3 *p_elements) \
- GDAPI_FUNC(godot_basis_get_axis, godot_vector3, const godot_basis *p_self, const godot_int p_axis) \
- GDAPI_FUNC_VOID(godot_basis_set_axis, godot_basis *p_self, const godot_int p_axis, const godot_vector3 *p_value) \
- GDAPI_FUNC(godot_basis_get_row, godot_vector3, const godot_basis *p_self, const godot_int p_row) \
- GDAPI_FUNC_VOID(godot_basis_set_row, godot_basis *p_self, const godot_int p_row, const godot_vector3 *p_value) \
- GDAPI_FUNC(godot_basis_operator_equal, godot_bool, const godot_basis *p_self, const godot_basis *p_b) \
- GDAPI_FUNC(godot_basis_operator_add, godot_basis, const godot_basis *p_self, const godot_basis *p_b) \
- GDAPI_FUNC(godot_basis_operator_substract, godot_basis, const godot_basis *p_self, const godot_basis *p_b) \
- GDAPI_FUNC(godot_basis_operator_multiply_vector, godot_basis, const godot_basis *p_self, const godot_basis *p_b) \
- GDAPI_FUNC(godot_basis_operator_multiply_scalar, godot_basis, const godot_basis *p_self, const godot_real p_b) \
- GDAPI_FUNC_VOID(godot_vector3_new, godot_vector3 *r_dest, const godot_real p_x, const godot_real p_y, const godot_real p_z) \
- GDAPI_FUNC(godot_vector3_as_string, godot_string, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_min_axis, godot_int, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_max_axis, godot_int, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_length, godot_real, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_length_squared, godot_real, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_is_normalized, godot_bool, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_normalized, godot_vector3, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_inverse, godot_vector3, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_snapped, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_by) \
- GDAPI_FUNC(godot_vector3_rotated, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_axis, const godot_real p_phi) \
- GDAPI_FUNC(godot_vector3_linear_interpolate, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_b, const godot_real p_t) \
- GDAPI_FUNC(godot_vector3_cubic_interpolate, godot_vector3, 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) \
- GDAPI_FUNC(godot_vector3_dot, godot_real, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_cross, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_outer, godot_basis, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_to_diagonal_matrix, godot_basis, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_abs, godot_vector3, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_floor, godot_vector3, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_ceil, godot_vector3, const godot_vector3 *p_self) \
- GDAPI_FUNC(godot_vector3_distance_to, godot_real, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_distance_squared_to, godot_real, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_angle_to, godot_real, const godot_vector3 *p_self, const godot_vector3 *p_to) \
- GDAPI_FUNC(godot_vector3_slide, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_n) \
- GDAPI_FUNC(godot_vector3_bounce, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_n) \
- GDAPI_FUNC(godot_vector3_reflect, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_n) \
- GDAPI_FUNC(godot_vector3_operator_add, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_operator_substract, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_operator_multiply_vector, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_operator_multiply_scalar, godot_vector3, const godot_vector3 *p_self, const godot_real p_b) \
- GDAPI_FUNC(godot_vector3_operator_divide_vector, godot_vector3, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_operator_divide_scalar, godot_vector3, const godot_vector3 *p_self, const godot_real p_b) \
- GDAPI_FUNC(godot_vector3_operator_equal, godot_bool, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_operator_less, godot_bool, const godot_vector3 *p_self, const godot_vector3 *p_b) \
- GDAPI_FUNC(godot_vector3_operator_neg, godot_vector3, const godot_vector3 *p_self) \
- GDAPI_FUNC_VOID(godot_vector3_set_axis, godot_vector3 *p_self, const godot_vector3_axis p_axis, const godot_real p_val) \
- GDAPI_FUNC(godot_vector3_get_axis, godot_real, const godot_vector3 *p_self, const godot_vector3_axis p_axis) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_new, godot_pool_byte_array *r_dest) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_new_copy, godot_pool_byte_array *r_dest, const godot_pool_byte_array *p_src) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_new_with_array, godot_pool_byte_array *r_dest, const godot_array *p_a) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_append, godot_pool_byte_array *p_self, const uint8_t p_data) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_append_array, godot_pool_byte_array *p_self, const godot_pool_byte_array *p_array) \
- GDAPI_FUNC(godot_pool_byte_array_insert, godot_error, godot_pool_byte_array *p_self, const godot_int p_idx, const uint8_t p_data) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_invert, godot_pool_byte_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_push_back, godot_pool_byte_array *p_self, const uint8_t p_data) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_remove, godot_pool_byte_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_resize, godot_pool_byte_array *p_self, const godot_int p_size) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_set, godot_pool_byte_array *p_self, const godot_int p_idx, const uint8_t p_data) \
- GDAPI_FUNC(godot_pool_byte_array_get, uint8_t, const godot_pool_byte_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_pool_byte_array_size, godot_int, const godot_pool_byte_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_byte_array_destroy, godot_pool_byte_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_int_array_new, godot_pool_int_array *r_dest) \
- GDAPI_FUNC_VOID(godot_pool_int_array_new_copy, godot_pool_int_array *r_dest, const godot_pool_int_array *p_src) \
- GDAPI_FUNC_VOID(godot_pool_int_array_new_with_array, godot_pool_int_array *r_dest, const godot_array *p_a) \
- GDAPI_FUNC_VOID(godot_pool_int_array_append, godot_pool_int_array *p_self, const godot_int p_data) \
- GDAPI_FUNC_VOID(godot_pool_int_array_append_array, godot_pool_int_array *p_self, const godot_pool_int_array *p_array) \
- GDAPI_FUNC(godot_pool_int_array_insert, godot_error, godot_pool_int_array *p_self, const godot_int p_idx, const godot_int p_data) \
- GDAPI_FUNC_VOID(godot_pool_int_array_invert, godot_pool_int_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_int_array_push_back, godot_pool_int_array *p_self, const godot_int p_data) \
- GDAPI_FUNC_VOID(godot_pool_int_array_remove, godot_pool_int_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_pool_int_array_resize, godot_pool_int_array *p_self, const godot_int p_size) \
- GDAPI_FUNC_VOID(godot_pool_int_array_set, godot_pool_int_array *p_self, const godot_int p_idx, const godot_int p_data) \
- GDAPI_FUNC(godot_pool_int_array_get, godot_int, const godot_pool_int_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_pool_int_array_size, godot_int, const godot_pool_int_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_int_array_destroy, godot_pool_int_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_real_array_new, godot_pool_real_array *r_dest) \
- GDAPI_FUNC_VOID(godot_pool_real_array_new_copy, godot_pool_real_array *r_dest, const godot_pool_real_array *p_src) \
- GDAPI_FUNC_VOID(godot_pool_real_array_new_with_array, godot_pool_real_array *r_dest, const godot_array *p_a) \
- GDAPI_FUNC_VOID(godot_pool_real_array_append, godot_pool_real_array *p_self, const godot_real p_data) \
- GDAPI_FUNC_VOID(godot_pool_real_array_append_array, godot_pool_real_array *p_self, const godot_pool_real_array *p_array) \
- GDAPI_FUNC(godot_pool_real_array_insert, godot_error, godot_pool_real_array *p_self, const godot_int p_idx, const godot_real p_data) \
- GDAPI_FUNC_VOID(godot_pool_real_array_invert, godot_pool_real_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_real_array_push_back, godot_pool_real_array *p_self, const godot_real p_data) \
- GDAPI_FUNC_VOID(godot_pool_real_array_remove, godot_pool_real_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_pool_real_array_resize, godot_pool_real_array *p_self, const godot_int p_size) \
- GDAPI_FUNC_VOID(godot_pool_real_array_set, godot_pool_real_array *p_self, const godot_int p_idx, const godot_real p_data) \
- GDAPI_FUNC(godot_pool_real_array_get, godot_real, const godot_pool_real_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_pool_real_array_size, godot_int, const godot_pool_real_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_real_array_destroy, godot_pool_real_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_string_array_new, godot_pool_string_array *r_dest) \
- GDAPI_FUNC_VOID(godot_pool_string_array_new_copy, godot_pool_string_array *r_dest, const godot_pool_string_array *p_src) \
- GDAPI_FUNC_VOID(godot_pool_string_array_new_with_array, godot_pool_string_array *r_dest, const godot_array *p_a) \
- GDAPI_FUNC_VOID(godot_pool_string_array_append, godot_pool_string_array *p_self, const godot_string *p_data) \
- GDAPI_FUNC_VOID(godot_pool_string_array_append_array, godot_pool_string_array *p_self, const godot_pool_string_array *p_array) \
- GDAPI_FUNC(godot_pool_string_array_insert, godot_error, godot_pool_string_array *p_self, const godot_int p_idx, const godot_string *p_data) \
- GDAPI_FUNC_VOID(godot_pool_string_array_invert, godot_pool_string_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_string_array_push_back, godot_pool_string_array *p_self, const godot_string *p_data) \
- GDAPI_FUNC_VOID(godot_pool_string_array_remove, godot_pool_string_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_pool_string_array_resize, godot_pool_string_array *p_self, const godot_int p_size) \
- GDAPI_FUNC_VOID(godot_pool_string_array_set, godot_pool_string_array *p_self, const godot_int p_idx, const godot_string *p_data) \
- GDAPI_FUNC(godot_pool_string_array_get, godot_string, const godot_pool_string_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_pool_string_array_size, godot_int, const godot_pool_string_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_string_array_destroy, godot_pool_string_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_new, godot_pool_vector2_array *r_dest) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_new_copy, godot_pool_vector2_array *r_dest, const godot_pool_vector2_array *p_src) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_new_with_array, godot_pool_vector2_array *r_dest, const godot_array *p_a) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_append, godot_pool_vector2_array *p_self, const godot_vector2 *p_data) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_append_array, godot_pool_vector2_array *p_self, const godot_pool_vector2_array *p_array) \
- GDAPI_FUNC(godot_pool_vector2_array_insert, godot_error, godot_pool_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_invert, godot_pool_vector2_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_push_back, godot_pool_vector2_array *p_self, const godot_vector2 *p_data) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_remove, godot_pool_vector2_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_resize, godot_pool_vector2_array *p_self, const godot_int p_size) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_set, godot_pool_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data) \
- GDAPI_FUNC(godot_pool_vector2_array_get, godot_vector2, const godot_pool_vector2_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_pool_vector2_array_size, godot_int, const godot_pool_vector2_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_vector2_array_destroy, godot_pool_vector2_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_new, godot_pool_vector3_array *r_dest) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_new_copy, godot_pool_vector3_array *r_dest, const godot_pool_vector3_array *p_src) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_new_with_array, godot_pool_vector3_array *r_dest, const godot_array *p_a) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_append, godot_pool_vector3_array *p_self, const godot_vector3 *p_data) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_append_array, godot_pool_vector3_array *p_self, const godot_pool_vector3_array *p_array) \
- GDAPI_FUNC(godot_pool_vector3_array_insert, godot_error, godot_pool_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_invert, godot_pool_vector3_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_push_back, godot_pool_vector3_array *p_self, const godot_vector3 *p_data) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_remove, godot_pool_vector3_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_resize, godot_pool_vector3_array *p_self, const godot_int p_size) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_set, godot_pool_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data) \
- GDAPI_FUNC(godot_pool_vector3_array_get, godot_vector3, const godot_pool_vector3_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_pool_vector3_array_size, godot_int, const godot_pool_vector3_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_vector3_array_destroy, godot_pool_vector3_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_color_array_new, godot_pool_color_array *r_dest) \
- GDAPI_FUNC_VOID(godot_pool_color_array_new_copy, godot_pool_color_array *r_dest, const godot_pool_color_array *p_src) \
- GDAPI_FUNC_VOID(godot_pool_color_array_new_with_array, godot_pool_color_array *r_dest, const godot_array *p_a) \
- GDAPI_FUNC_VOID(godot_pool_color_array_append, godot_pool_color_array *p_self, const godot_color *p_data) \
- GDAPI_FUNC_VOID(godot_pool_color_array_append_array, godot_pool_color_array *p_self, const godot_pool_color_array *p_array) \
- GDAPI_FUNC(godot_pool_color_array_insert, godot_error, godot_pool_color_array *p_self, const godot_int p_idx, const godot_color *p_data) \
- GDAPI_FUNC_VOID(godot_pool_color_array_invert, godot_pool_color_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_color_array_push_back, godot_pool_color_array *p_self, const godot_color *p_data) \
- GDAPI_FUNC_VOID(godot_pool_color_array_remove, godot_pool_color_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_pool_color_array_resize, godot_pool_color_array *p_self, const godot_int p_size) \
- GDAPI_FUNC_VOID(godot_pool_color_array_set, godot_pool_color_array *p_self, const godot_int p_idx, const godot_color *p_data) \
- GDAPI_FUNC(godot_pool_color_array_get, godot_color, const godot_pool_color_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_pool_color_array_size, godot_int, const godot_pool_color_array *p_self) \
- GDAPI_FUNC_VOID(godot_pool_color_array_destroy, godot_pool_color_array *p_self) \
- GDAPI_FUNC_VOID(godot_array_new, godot_array *r_dest) \
- GDAPI_FUNC_VOID(godot_array_new_copy, godot_array *r_dest, const godot_array *p_src) \
- GDAPI_FUNC_VOID(godot_array_new_pool_color_array, godot_array *r_dest, const godot_pool_color_array *p_pca) \
- GDAPI_FUNC_VOID(godot_array_new_pool_vector3_array, godot_array *r_dest, const godot_pool_vector3_array *p_pv3a) \
- GDAPI_FUNC_VOID(godot_array_new_pool_vector2_array, godot_array *r_dest, const godot_pool_vector2_array *p_pv2a) \
- GDAPI_FUNC_VOID(godot_array_new_pool_string_array, godot_array *r_dest, const godot_pool_string_array *p_psa) \
- GDAPI_FUNC_VOID(godot_array_new_pool_real_array, godot_array *r_dest, const godot_pool_real_array *p_pra) \
- GDAPI_FUNC_VOID(godot_array_new_pool_int_array, godot_array *r_dest, const godot_pool_int_array *p_pia) \
- GDAPI_FUNC_VOID(godot_array_new_pool_byte_array, godot_array *r_dest, const godot_pool_byte_array *p_pba) \
- GDAPI_FUNC_VOID(godot_array_set, godot_array *p_self, const godot_int p_idx, const godot_variant *p_value) \
- GDAPI_FUNC(godot_array_get, godot_variant, const godot_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_array_operator_index, godot_variant *, godot_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_array_append, godot_array *p_self, const godot_variant *p_value) \
- GDAPI_FUNC_VOID(godot_array_clear, godot_array *p_self) \
- GDAPI_FUNC(godot_array_count, godot_int, const godot_array *p_self, const godot_variant *p_value) \
- GDAPI_FUNC(godot_array_empty, godot_bool, const godot_array *p_self) \
- GDAPI_FUNC_VOID(godot_array_erase, godot_array *p_self, const godot_variant *p_value) \
- GDAPI_FUNC(godot_array_front, godot_variant, const godot_array *p_self) \
- GDAPI_FUNC(godot_array_back, godot_variant, const godot_array *p_self) \
- GDAPI_FUNC(godot_array_find, godot_int, const godot_array *p_self, const godot_variant *p_what, const godot_int p_from) \
- GDAPI_FUNC(godot_array_find_last, godot_int, const godot_array *p_self, const godot_variant *p_what) \
- GDAPI_FUNC(godot_array_has, godot_bool, const godot_array *p_self, const godot_variant *p_value) \
- GDAPI_FUNC(godot_array_hash, godot_int, const godot_array *p_self) \
- GDAPI_FUNC_VOID(godot_array_insert, godot_array *p_self, const godot_int p_pos, const godot_variant *p_value) \
- GDAPI_FUNC_VOID(godot_array_invert, godot_array *p_self) \
- GDAPI_FUNC(godot_array_pop_back, godot_variant, godot_array *p_self) \
- GDAPI_FUNC(godot_array_pop_front, godot_variant, godot_array *p_self) \
- GDAPI_FUNC_VOID(godot_array_push_back, godot_array *p_self, const godot_variant *p_value) \
- GDAPI_FUNC_VOID(godot_array_push_front, godot_array *p_self, const godot_variant *p_value) \
- GDAPI_FUNC_VOID(godot_array_remove, godot_array *p_self, const godot_int p_idx) \
- GDAPI_FUNC_VOID(godot_array_resize, godot_array *p_self, const godot_int p_size) \
- GDAPI_FUNC(godot_array_rfind, godot_int, const godot_array *p_self, const godot_variant *p_what, const godot_int p_from) \
- GDAPI_FUNC(godot_array_size, godot_int, const godot_array *p_self) \
- GDAPI_FUNC_VOID(godot_array_sort, godot_array *p_self) \
- GDAPI_FUNC_VOID(godot_array_sort_custom, godot_array *p_self, godot_object *p_obj, const godot_string *p_func) \
- GDAPI_FUNC_VOID(godot_array_destroy, godot_array *p_self) \
- GDAPI_FUNC_VOID(godot_dictionary_new, godot_dictionary *r_dest) \
- GDAPI_FUNC_VOID(godot_dictionary_new_copy, godot_dictionary *r_dest, const godot_dictionary *p_src) \
- GDAPI_FUNC_VOID(godot_dictionary_destroy, godot_dictionary *p_self) \
- GDAPI_FUNC(godot_dictionary_size, godot_int, const godot_dictionary *p_self) \
- GDAPI_FUNC(godot_dictionary_empty, godot_bool, const godot_dictionary *p_self) \
- GDAPI_FUNC_VOID(godot_dictionary_clear, godot_dictionary *p_self) \
- GDAPI_FUNC(godot_dictionary_has, godot_bool, const godot_dictionary *p_self, const godot_variant *p_key) \
- GDAPI_FUNC(godot_dictionary_has_all, godot_bool, const godot_dictionary *p_self, const godot_array *p_keys) \
- GDAPI_FUNC_VOID(godot_dictionary_erase, godot_dictionary *p_self, const godot_variant *p_key) \
- GDAPI_FUNC(godot_dictionary_hash, godot_int, const godot_dictionary *p_self) \
- GDAPI_FUNC(godot_dictionary_keys, godot_array, const godot_dictionary *p_self) \
- GDAPI_FUNC(godot_dictionary_values, godot_array, const godot_dictionary *p_self) \
- GDAPI_FUNC(godot_dictionary_get, godot_variant, const godot_dictionary *p_self, const godot_variant *p_key) \
- GDAPI_FUNC_VOID(godot_dictionary_set, godot_dictionary *p_self, const godot_variant *p_key, const godot_variant *p_value) \
- GDAPI_FUNC(godot_dictionary_operator_index, godot_variant *, godot_dictionary *p_self, const godot_variant *p_key) \
- GDAPI_FUNC(godot_dictionary_next, godot_variant *, const godot_dictionary *p_self, const godot_variant *p_key) \
- GDAPI_FUNC(godot_dictionary_operator_equal, godot_bool, const godot_dictionary *p_self, const godot_dictionary *p_b) \
- GDAPI_FUNC(godot_dictionary_to_json, godot_string, const godot_dictionary *p_self) \
- GDAPI_FUNC_VOID(godot_node_path_new, godot_node_path *r_dest, const godot_string *p_from) \
- GDAPI_FUNC_VOID(godot_node_path_new_copy, godot_node_path *r_dest, const godot_node_path *p_src) \
- GDAPI_FUNC_VOID(godot_node_path_destroy, godot_node_path *p_self) \
- GDAPI_FUNC(godot_node_path_as_string, godot_string, const godot_node_path *p_self) \
- GDAPI_FUNC(godot_node_path_is_absolute, godot_bool, const godot_node_path *p_self) \
- GDAPI_FUNC(godot_node_path_get_name_count, godot_int, const godot_node_path *p_self) \
- GDAPI_FUNC(godot_node_path_get_name, godot_string, const godot_node_path *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_node_path_get_subname_count, godot_int, const godot_node_path *p_self) \
- GDAPI_FUNC(godot_node_path_get_subname, godot_string, const godot_node_path *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_node_path_get_property, godot_string, const godot_node_path *p_self) \
- GDAPI_FUNC(godot_node_path_is_empty, godot_bool, const godot_node_path *p_self) \
- GDAPI_FUNC(godot_node_path_operator_equal, godot_bool, const godot_node_path *p_self, const godot_node_path *p_b) \
- GDAPI_FUNC_VOID(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) \
- GDAPI_FUNC_VOID(godot_plane_new_with_vectors, godot_plane *r_dest, const godot_vector3 *p_v1, const godot_vector3 *p_v2, const godot_vector3 *p_v3) \
- GDAPI_FUNC_VOID(godot_plane_new_with_normal, godot_plane *r_dest, const godot_vector3 *p_normal, const godot_real p_d) \
- GDAPI_FUNC(godot_plane_as_string, godot_string, const godot_plane *p_self) \
- GDAPI_FUNC(godot_plane_normalized, godot_plane, const godot_plane *p_self) \
- GDAPI_FUNC(godot_plane_center, godot_vector3, const godot_plane *p_self) \
- GDAPI_FUNC(godot_plane_get_any_point, godot_vector3, const godot_plane *p_self) \
- GDAPI_FUNC(godot_plane_is_point_over, godot_bool, const godot_plane *p_self, const godot_vector3 *p_point) \
- GDAPI_FUNC(godot_plane_distance_to, godot_real, const godot_plane *p_self, const godot_vector3 *p_point) \
- GDAPI_FUNC(godot_plane_has_point, godot_bool, const godot_plane *p_self, const godot_vector3 *p_point, const godot_real p_epsilon) \
- GDAPI_FUNC(godot_plane_project, godot_vector3, const godot_plane *p_self, const godot_vector3 *p_point) \
- GDAPI_FUNC(godot_plane_intersect_3, godot_bool, const godot_plane *p_self, godot_vector3 *r_dest, const godot_plane *p_b, const godot_plane *p_c) \
- GDAPI_FUNC(godot_plane_intersects_ray, godot_bool, const godot_plane *p_self, godot_vector3 *r_dest, const godot_vector3 *p_from, const godot_vector3 *p_dir) \
- GDAPI_FUNC(godot_plane_intersects_segment, godot_bool, const godot_plane *p_self, godot_vector3 *r_dest, const godot_vector3 *p_begin, const godot_vector3 *p_end) \
- GDAPI_FUNC(godot_plane_operator_neg, godot_plane, const godot_plane *p_self) \
- GDAPI_FUNC(godot_plane_operator_equal, godot_bool, const godot_plane *p_self, const godot_plane *p_b) \
- GDAPI_FUNC_VOID(godot_plane_set_normal, godot_plane *p_self, const godot_vector3 *p_normal) \
- GDAPI_FUNC(godot_plane_get_normal, godot_vector3, const godot_plane *p_self) \
- GDAPI_FUNC(godot_plane_get_d, godot_real, const godot_plane *p_self) \
- GDAPI_FUNC_VOID(godot_plane_set_d, godot_plane *p_self, const godot_real p_d) \
- GDAPI_FUNC_VOID(godot_rect2_new_with_position_and_size, godot_rect2 *r_dest, const godot_vector2 *p_pos, const godot_vector2 *p_size) \
- GDAPI_FUNC_VOID(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) \
- GDAPI_FUNC(godot_rect2_as_string, godot_string, const godot_rect2 *p_self) \
- GDAPI_FUNC(godot_rect2_get_area, godot_real, const godot_rect2 *p_self) \
- GDAPI_FUNC(godot_rect2_intersects, godot_bool, const godot_rect2 *p_self, const godot_rect2 *p_b) \
- GDAPI_FUNC(godot_rect2_encloses, godot_bool, const godot_rect2 *p_self, const godot_rect2 *p_b) \
- GDAPI_FUNC(godot_rect2_has_no_area, godot_bool, const godot_rect2 *p_self) \
- GDAPI_FUNC(godot_rect2_clip, godot_rect2, const godot_rect2 *p_self, const godot_rect2 *p_b) \
- GDAPI_FUNC(godot_rect2_merge, godot_rect2, const godot_rect2 *p_self, const godot_rect2 *p_b) \
- GDAPI_FUNC(godot_rect2_has_point, godot_bool, const godot_rect2 *p_self, const godot_vector2 *p_point) \
- GDAPI_FUNC(godot_rect2_grow, godot_rect2, const godot_rect2 *p_self, const godot_real p_by) \
- GDAPI_FUNC(godot_rect2_expand, godot_rect2, const godot_rect2 *p_self, const godot_vector2 *p_to) \
- GDAPI_FUNC(godot_rect2_operator_equal, godot_bool, const godot_rect2 *p_self, const godot_rect2 *p_b) \
- GDAPI_FUNC(godot_rect2_get_position, godot_vector2, const godot_rect2 *p_self) \
- GDAPI_FUNC(godot_rect2_get_size, godot_vector2, const godot_rect2 *p_self) \
- GDAPI_FUNC_VOID(godot_rect2_set_position, godot_rect2 *p_self, const godot_vector2 *p_pos) \
- GDAPI_FUNC_VOID(godot_rect2_set_size, godot_rect2 *p_self, const godot_vector2 *p_size) \
- GDAPI_FUNC_VOID(godot_rect3_new, godot_rect3 *r_dest, const godot_vector3 *p_pos, const godot_vector3 *p_size) \
- GDAPI_FUNC(godot_rect3_get_position, godot_vector3, const godot_rect3 *p_self) \
- GDAPI_FUNC_VOID(godot_rect3_set_position, const godot_rect3 *p_self, const godot_vector3 *p_v) \
- GDAPI_FUNC(godot_rect3_get_size, godot_vector3, const godot_rect3 *p_self) \
- GDAPI_FUNC_VOID(godot_rect3_set_size, const godot_rect3 *p_self, const godot_vector3 *p_v) \
- GDAPI_FUNC(godot_rect3_as_string, godot_string, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_get_area, godot_real, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_has_no_area, godot_bool, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_has_no_surface, godot_bool, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_intersects, godot_bool, const godot_rect3 *p_self, const godot_rect3 *p_with) \
- GDAPI_FUNC(godot_rect3_encloses, godot_bool, const godot_rect3 *p_self, const godot_rect3 *p_with) \
- GDAPI_FUNC(godot_rect3_merge, godot_rect3, const godot_rect3 *p_self, const godot_rect3 *p_with) \
- GDAPI_FUNC(godot_rect3_intersection, godot_rect3, const godot_rect3 *p_self, const godot_rect3 *p_with) \
- GDAPI_FUNC(godot_rect3_intersects_plane, godot_bool, const godot_rect3 *p_self, const godot_plane *p_plane) \
- GDAPI_FUNC(godot_rect3_intersects_segment, godot_bool, const godot_rect3 *p_self, const godot_vector3 *p_from, const godot_vector3 *p_to) \
- GDAPI_FUNC(godot_rect3_has_point, godot_bool, const godot_rect3 *p_self, const godot_vector3 *p_point) \
- GDAPI_FUNC(godot_rect3_get_support, godot_vector3, const godot_rect3 *p_self, const godot_vector3 *p_dir) \
- GDAPI_FUNC(godot_rect3_get_longest_axis, godot_vector3, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_get_longest_axis_index, godot_int, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_get_longest_axis_size, godot_real, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_get_shortest_axis, godot_vector3, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_get_shortest_axis_index, godot_int, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_get_shortest_axis_size, godot_real, const godot_rect3 *p_self) \
- GDAPI_FUNC(godot_rect3_expand, godot_rect3, const godot_rect3 *p_self, const godot_vector3 *p_to_point) \
- GDAPI_FUNC(godot_rect3_grow, godot_rect3, const godot_rect3 *p_self, const godot_real p_by) \
- GDAPI_FUNC(godot_rect3_get_endpoint, godot_vector3, const godot_rect3 *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_rect3_operator_equal, godot_bool, const godot_rect3 *p_self, const godot_rect3 *p_b) \
- GDAPI_FUNC_VOID(godot_rid_new, godot_rid *r_dest) \
- GDAPI_FUNC(godot_rid_get_id, godot_int, const godot_rid *p_self) \
- GDAPI_FUNC_VOID(godot_rid_new_with_resource, godot_rid *r_dest, const godot_object *p_from) \
- GDAPI_FUNC(godot_rid_operator_equal, godot_bool, const godot_rid *p_self, const godot_rid *p_b) \
- GDAPI_FUNC(godot_rid_operator_less, godot_bool, const godot_rid *p_self, const godot_rid *p_b) \
- GDAPI_FUNC_VOID(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) \
- GDAPI_FUNC_VOID(godot_transform_new, godot_transform *r_dest, const godot_basis *p_basis, const godot_vector3 *p_origin) \
- GDAPI_FUNC(godot_transform_get_basis, godot_basis, const godot_transform *p_self) \
- GDAPI_FUNC_VOID(godot_transform_set_basis, godot_transform *p_self, godot_basis *p_v) \
- GDAPI_FUNC(godot_transform_get_origin, godot_vector3, const godot_transform *p_self) \
- GDAPI_FUNC_VOID(godot_transform_set_origin, godot_transform *p_self, godot_vector3 *p_v) \
- GDAPI_FUNC(godot_transform_as_string, godot_string, const godot_transform *p_self) \
- GDAPI_FUNC(godot_transform_inverse, godot_transform, const godot_transform *p_self) \
- GDAPI_FUNC(godot_transform_affine_inverse, godot_transform, const godot_transform *p_self) \
- GDAPI_FUNC(godot_transform_orthonormalized, godot_transform, const godot_transform *p_self) \
- GDAPI_FUNC(godot_transform_rotated, godot_transform, const godot_transform *p_self, const godot_vector3 *p_axis, const godot_real p_phi) \
- GDAPI_FUNC(godot_transform_scaled, godot_transform, const godot_transform *p_self, const godot_vector3 *p_scale) \
- GDAPI_FUNC(godot_transform_translated, godot_transform, const godot_transform *p_self, const godot_vector3 *p_ofs) \
- GDAPI_FUNC(godot_transform_looking_at, godot_transform, const godot_transform *p_self, const godot_vector3 *p_target, const godot_vector3 *p_up) \
- GDAPI_FUNC(godot_transform_xform_plane, godot_plane, const godot_transform *p_self, const godot_plane *p_v) \
- GDAPI_FUNC(godot_transform_xform_inv_plane, godot_plane, const godot_transform *p_self, const godot_plane *p_v) \
- GDAPI_FUNC_VOID(godot_transform_new_identity, godot_transform *r_dest) \
- GDAPI_FUNC(godot_transform_operator_equal, godot_bool, const godot_transform *p_self, const godot_transform *p_b) \
- GDAPI_FUNC(godot_transform_operator_multiply, godot_transform, const godot_transform *p_self, const godot_transform *p_b) \
- GDAPI_FUNC(godot_transform_xform_vector3, godot_vector3, const godot_transform *p_self, const godot_vector3 *p_v) \
- GDAPI_FUNC(godot_transform_xform_inv_vector3, godot_vector3, const godot_transform *p_self, const godot_vector3 *p_v) \
- GDAPI_FUNC(godot_transform_xform_rect3, godot_rect3, const godot_transform *p_self, const godot_rect3 *p_v) \
- GDAPI_FUNC(godot_transform_xform_inv_rect3, godot_rect3, const godot_transform *p_self, const godot_rect3 *p_v) \
- GDAPI_FUNC_VOID(godot_transform2d_new, godot_transform2d *r_dest, const godot_real p_rot, const godot_vector2 *p_pos) \
- GDAPI_FUNC_VOID(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) \
- GDAPI_FUNC(godot_transform2d_as_string, godot_string, const godot_transform2d *p_self) \
- GDAPI_FUNC(godot_transform2d_inverse, godot_transform2d, const godot_transform2d *p_self) \
- GDAPI_FUNC(godot_transform2d_affine_inverse, godot_transform2d, const godot_transform2d *p_self) \
- GDAPI_FUNC(godot_transform2d_get_rotation, godot_real, const godot_transform2d *p_self) \
- GDAPI_FUNC(godot_transform2d_get_origin, godot_vector2, const godot_transform2d *p_self) \
- GDAPI_FUNC(godot_transform2d_get_scale, godot_vector2, const godot_transform2d *p_self) \
- GDAPI_FUNC(godot_transform2d_orthonormalized, godot_transform2d, const godot_transform2d *p_self) \
- GDAPI_FUNC(godot_transform2d_rotated, godot_transform2d, const godot_transform2d *p_self, const godot_real p_phi) \
- GDAPI_FUNC(godot_transform2d_scaled, godot_transform2d, const godot_transform2d *p_self, const godot_vector2 *p_scale) \
- GDAPI_FUNC(godot_transform2d_translated, godot_transform2d, const godot_transform2d *p_self, const godot_vector2 *p_offset) \
- GDAPI_FUNC(godot_transform2d_xform_vector2, godot_vector2, const godot_transform2d *p_self, const godot_vector2 *p_v) \
- GDAPI_FUNC(godot_transform2d_xform_inv_vector2, godot_vector2, const godot_transform2d *p_self, const godot_vector2 *p_v) \
- GDAPI_FUNC(godot_transform2d_basis_xform_vector2, godot_vector2, const godot_transform2d *p_self, const godot_vector2 *p_v) \
- GDAPI_FUNC(godot_transform2d_basis_xform_inv_vector2, godot_vector2, const godot_transform2d *p_self, const godot_vector2 *p_v) \
- GDAPI_FUNC(godot_transform2d_interpolate_with, godot_transform2d, const godot_transform2d *p_self, const godot_transform2d *p_m, const godot_real p_c) \
- GDAPI_FUNC(godot_transform2d_operator_equal, godot_bool, const godot_transform2d *p_self, const godot_transform2d *p_b) \
- GDAPI_FUNC(godot_transform2d_operator_multiply, godot_transform2d, const godot_transform2d *p_self, const godot_transform2d *p_b) \
- GDAPI_FUNC_VOID(godot_transform2d_new_identity, godot_transform2d *r_dest) \
- GDAPI_FUNC(godot_transform2d_xform_rect2, godot_rect2, const godot_transform2d *p_self, const godot_rect2 *p_v) \
- GDAPI_FUNC(godot_transform2d_xform_inv_rect2, godot_rect2, const godot_transform2d *p_self, const godot_rect2 *p_v) \
- GDAPI_FUNC(godot_variant_get_type, godot_variant_type, const godot_variant *p_v) \
- GDAPI_FUNC_VOID(godot_variant_new_copy, godot_variant *r_dest, const godot_variant *p_src) \
- GDAPI_FUNC_VOID(godot_variant_new_nil, godot_variant *r_dest) \
- GDAPI_FUNC_VOID(godot_variant_new_bool, godot_variant *p_v, const godot_bool p_b) \
- GDAPI_FUNC_VOID(godot_variant_new_uint, godot_variant *r_dest, const uint64_t p_i) \
- GDAPI_FUNC_VOID(godot_variant_new_int, godot_variant *r_dest, const int64_t p_i) \
- GDAPI_FUNC_VOID(godot_variant_new_real, godot_variant *r_dest, const double p_r) \
- GDAPI_FUNC_VOID(godot_variant_new_string, godot_variant *r_dest, const godot_string *p_s) \
- GDAPI_FUNC_VOID(godot_variant_new_vector2, godot_variant *r_dest, const godot_vector2 *p_v2) \
- GDAPI_FUNC_VOID(godot_variant_new_rect2, godot_variant *r_dest, const godot_rect2 *p_rect2) \
- GDAPI_FUNC_VOID(godot_variant_new_vector3, godot_variant *r_dest, const godot_vector3 *p_v3) \
- GDAPI_FUNC_VOID(godot_variant_new_transform2d, godot_variant *r_dest, const godot_transform2d *p_t2d) \
- GDAPI_FUNC_VOID(godot_variant_new_plane, godot_variant *r_dest, const godot_plane *p_plane) \
- GDAPI_FUNC_VOID(godot_variant_new_quat, godot_variant *r_dest, const godot_quat *p_quat) \
- GDAPI_FUNC_VOID(godot_variant_new_rect3, godot_variant *r_dest, const godot_rect3 *p_rect3) \
- GDAPI_FUNC_VOID(godot_variant_new_basis, godot_variant *r_dest, const godot_basis *p_basis) \
- GDAPI_FUNC_VOID(godot_variant_new_transform, godot_variant *r_dest, const godot_transform *p_trans) \
- GDAPI_FUNC_VOID(godot_variant_new_color, godot_variant *r_dest, const godot_color *p_color) \
- GDAPI_FUNC_VOID(godot_variant_new_node_path, godot_variant *r_dest, const godot_node_path *p_np) \
- GDAPI_FUNC_VOID(godot_variant_new_rid, godot_variant *r_dest, const godot_rid *p_rid) \
- GDAPI_FUNC_VOID(godot_variant_new_object, godot_variant *r_dest, const godot_object *p_obj) \
- GDAPI_FUNC_VOID(godot_variant_new_dictionary, godot_variant *r_dest, const godot_dictionary *p_dict) \
- GDAPI_FUNC_VOID(godot_variant_new_array, godot_variant *r_dest, const godot_array *p_arr) \
- GDAPI_FUNC_VOID(godot_variant_new_pool_byte_array, godot_variant *r_dest, const godot_pool_byte_array *p_pba) \
- GDAPI_FUNC_VOID(godot_variant_new_pool_int_array, godot_variant *r_dest, const godot_pool_int_array *p_pia) \
- GDAPI_FUNC_VOID(godot_variant_new_pool_real_array, godot_variant *r_dest, const godot_pool_real_array *p_pra) \
- GDAPI_FUNC_VOID(godot_variant_new_pool_string_array, godot_variant *r_dest, const godot_pool_string_array *p_psa) \
- GDAPI_FUNC_VOID(godot_variant_new_pool_vector2_array, godot_variant *r_dest, const godot_pool_vector2_array *p_pv2a) \
- GDAPI_FUNC_VOID(godot_variant_new_pool_vector3_array, godot_variant *r_dest, const godot_pool_vector3_array *p_pv3a) \
- GDAPI_FUNC_VOID(godot_variant_new_pool_color_array, godot_variant *r_dest, const godot_pool_color_array *p_pca) \
- GDAPI_FUNC(godot_variant_as_bool, godot_bool, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_uint, uint64_t, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_int, int64_t, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_real, double, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_string, godot_string, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_vector2, godot_vector2, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_rect2, godot_rect2, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_vector3, godot_vector3, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_transform2d, godot_transform2d, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_plane, godot_plane, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_quat, godot_quat, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_rect3, godot_rect3, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_basis, godot_basis, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_transform, godot_transform, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_color, godot_color, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_node_path, godot_node_path, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_rid, godot_rid, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_object, godot_object *, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_dictionary, godot_dictionary, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_array, godot_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_pool_byte_array, godot_pool_byte_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_pool_int_array, godot_pool_int_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_pool_real_array, godot_pool_real_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_pool_string_array, godot_pool_string_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_pool_vector2_array, godot_pool_vector2_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_pool_vector3_array, godot_pool_vector3_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_as_pool_color_array, godot_pool_color_array, const godot_variant *p_self) \
- GDAPI_FUNC(godot_variant_call, godot_variant, 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) \
- GDAPI_FUNC(godot_variant_has_method, godot_bool, const godot_variant *p_self, const godot_string *p_method) \
- GDAPI_FUNC(godot_variant_operator_equal, godot_bool, const godot_variant *p_self, const godot_variant *p_other) \
- GDAPI_FUNC(godot_variant_operator_less, godot_bool, const godot_variant *p_self, const godot_variant *p_other) \
- GDAPI_FUNC(godot_variant_hash_compare, godot_bool, const godot_variant *p_self, const godot_variant *p_other) \
- GDAPI_FUNC(godot_variant_booleanize, godot_bool, const godot_variant *p_self, godot_bool *r_valid) \
- GDAPI_FUNC_VOID(godot_variant_destroy, godot_variant *p_self) \
- GDAPI_FUNC_VOID(godot_string_new, godot_string *r_dest) \
- GDAPI_FUNC_VOID(godot_string_new_copy, godot_string *r_dest, const godot_string *p_src) \
- GDAPI_FUNC_VOID(godot_string_new_data, godot_string *r_dest, const char *p_contents, const int p_size) \
- GDAPI_FUNC_VOID(godot_string_new_unicode_data, godot_string *r_dest, const wchar_t *p_contents, const int p_size) \
- GDAPI_FUNC_VOID(godot_string_get_data, const godot_string *p_self, char *p_dest, int *p_size) \
- GDAPI_FUNC(godot_string_operator_index, wchar_t *, godot_string *p_self, const godot_int p_idx) \
- GDAPI_FUNC(godot_string_c_str, const char *, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_unicode_str, const wchar_t *, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_operator_equal, godot_bool, const godot_string *p_self, const godot_string *p_b) \
- GDAPI_FUNC(godot_string_operator_less, godot_bool, const godot_string *p_self, const godot_string *p_b) \
- GDAPI_FUNC(godot_string_operator_plus, godot_string, const godot_string *p_self, const godot_string *p_b) \
- GDAPI_FUNC(godot_string_length, godot_int, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_begins_with, godot_bool, const godot_string *p_self, const godot_string *p_string) \
- GDAPI_FUNC(godot_string_begins_with_char_array, godot_bool, const godot_string *p_self, const char *p_char_array) \
- GDAPI_FUNC(godot_string_bigrams, godot_array, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_chr, godot_string, wchar_t p_character) \
- GDAPI_FUNC(godot_string_ends_with, godot_bool, const godot_string *p_self, const godot_string *p_string) \
- GDAPI_FUNC(godot_string_find, godot_int, const godot_string *p_self, godot_string p_what) \
- GDAPI_FUNC(godot_string_find_from, godot_int, const godot_string *p_self, godot_string p_what, godot_int p_from) \
- GDAPI_FUNC(godot_string_findmk, godot_int, const godot_string *p_self, const godot_array *p_keys) \
- GDAPI_FUNC(godot_string_findmk_from, godot_int, const godot_string *p_self, const godot_array *p_keys, godot_int p_from) \
- GDAPI_FUNC(godot_string_findmk_from_in_place, godot_int, const godot_string *p_self, const godot_array *p_keys, godot_int p_from, godot_int *r_key) \
- GDAPI_FUNC(godot_string_findn, godot_int, const godot_string *p_self, godot_string p_what) \
- GDAPI_FUNC(godot_string_findn_from, godot_int, const godot_string *p_self, godot_string p_what, godot_int p_from) \
- GDAPI_FUNC(godot_string_find_last, godot_int, const godot_string *p_self, godot_string p_what) \
- GDAPI_FUNC(godot_string_format, godot_string, const godot_string *p_self, const godot_variant *p_values) \
- GDAPI_FUNC(godot_string_format_with_custom_placeholder, godot_string, const godot_string *p_self, const godot_variant *p_values, const char *p_placeholder) \
- GDAPI_FUNC(godot_string_hex_encode_buffer, godot_string, const uint8_t *p_buffer, godot_int p_len) \
- GDAPI_FUNC(godot_string_hex_to_int, godot_int, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_hex_to_int_without_prefix, godot_int, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_insert, godot_string, const godot_string *p_self, godot_int p_at_pos, godot_string p_string) \
- GDAPI_FUNC(godot_string_is_numeric, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_subsequence_of, godot_bool, const godot_string *p_self, const godot_string *p_string) \
- GDAPI_FUNC(godot_string_is_subsequence_ofi, godot_bool, const godot_string *p_self, const godot_string *p_string) \
- GDAPI_FUNC(godot_string_lpad, godot_string, const godot_string *p_self, godot_int p_min_length) \
- GDAPI_FUNC(godot_string_lpad_with_custom_character, godot_string, const godot_string *p_self, godot_int p_min_length, const godot_string *p_character) \
- GDAPI_FUNC(godot_string_match, godot_bool, const godot_string *p_self, const godot_string *p_wildcard) \
- GDAPI_FUNC(godot_string_matchn, godot_bool, const godot_string *p_self, const godot_string *p_wildcard) \
- GDAPI_FUNC(godot_string_md5, godot_string, const uint8_t *p_md5) \
- GDAPI_FUNC(godot_string_num, godot_string, double p_num) \
- GDAPI_FUNC(godot_string_num_int64, godot_string, int64_t p_num, godot_int p_base) \
- GDAPI_FUNC(godot_string_num_int64_capitalized, godot_string, int64_t p_num, godot_int p_base, godot_bool p_capitalize_hex) \
- GDAPI_FUNC(godot_string_num_real, godot_string, double p_num) \
- GDAPI_FUNC(godot_string_num_scientific, godot_string, double p_num) \
- GDAPI_FUNC(godot_string_num_with_decimals, godot_string, double p_num, godot_int p_decimals) \
- GDAPI_FUNC(godot_string_pad_decimals, godot_string, const godot_string *p_self, godot_int p_digits) \
- GDAPI_FUNC(godot_string_pad_zeros, godot_string, const godot_string *p_self, godot_int p_digits) \
- GDAPI_FUNC(godot_string_replace_first, godot_string, const godot_string *p_self, godot_string p_key, godot_string p_with) \
- GDAPI_FUNC(godot_string_replace, godot_string, const godot_string *p_self, godot_string p_key, godot_string p_with) \
- GDAPI_FUNC(godot_string_replacen, godot_string, const godot_string *p_self, godot_string p_key, godot_string p_with) \
- GDAPI_FUNC(godot_string_rfind, godot_int, const godot_string *p_self, godot_string p_what) \
- GDAPI_FUNC(godot_string_rfindn, godot_int, const godot_string *p_self, godot_string p_what) \
- GDAPI_FUNC(godot_string_rfind_from, godot_int, const godot_string *p_self, godot_string p_what, godot_int p_from) \
- GDAPI_FUNC(godot_string_rfindn_from, godot_int, const godot_string *p_self, godot_string p_what, godot_int p_from) \
- GDAPI_FUNC(godot_string_rpad, godot_string, const godot_string *p_self, godot_int p_min_length) \
- GDAPI_FUNC(godot_string_rpad_with_custom_character, godot_string, const godot_string *p_self, godot_int p_min_length, const godot_string *p_character) \
- GDAPI_FUNC(godot_string_similarity, godot_real, const godot_string *p_self, const godot_string *p_string) \
- GDAPI_FUNC(godot_string_sprintf, godot_string, const godot_string *p_self, const godot_array *p_values, godot_bool *p_error) \
- GDAPI_FUNC(godot_string_substr, godot_string, const godot_string *p_self, godot_int p_from, godot_int p_chars) \
- GDAPI_FUNC(godot_string_to_double, double, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_to_float, godot_real, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_to_int, godot_int, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_camelcase_to_underscore, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_camelcase_to_underscore_lowercased, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_capitalize, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_char_to_double, double, const char *p_what) \
- GDAPI_FUNC(godot_string_char_to_int, godot_int, const char *p_what) \
- GDAPI_FUNC(godot_string_wchar_to_int, int64_t, const wchar_t *p_str) \
- GDAPI_FUNC(godot_string_char_to_int_with_len, godot_int, const char *p_what, godot_int p_len) \
- GDAPI_FUNC(godot_string_char_to_int64_with_len, int64_t, const wchar_t *p_str, int p_len) \
- GDAPI_FUNC(godot_string_hex_to_int64, int64_t, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_hex_to_int64_with_prefix, int64_t, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_to_int64, int64_t, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_unicode_char_to_double, double, const wchar_t *p_str, const wchar_t **r_end) \
- GDAPI_FUNC(godot_string_get_slice_count, godot_int, const godot_string *p_self, godot_string p_splitter) \
- GDAPI_FUNC(godot_string_get_slice, godot_string, const godot_string *p_self, godot_string p_splitter, godot_int p_slice) \
- GDAPI_FUNC(godot_string_get_slicec, godot_string, const godot_string *p_self, wchar_t p_splitter, godot_int p_slice) \
- GDAPI_FUNC(godot_string_split, godot_array, const godot_string *p_self, const godot_string *p_splitter) \
- GDAPI_FUNC(godot_string_split_allow_empty, godot_array, const godot_string *p_self, const godot_string *p_splitter) \
- GDAPI_FUNC(godot_string_split_floats, godot_array, const godot_string *p_self, const godot_string *p_splitter) \
- GDAPI_FUNC(godot_string_split_floats_allows_empty, godot_array, const godot_string *p_self, const godot_string *p_splitter) \
- GDAPI_FUNC(godot_string_split_floats_mk, godot_array, const godot_string *p_self, const godot_array *p_splitters) \
- GDAPI_FUNC(godot_string_split_floats_mk_allows_empty, godot_array, const godot_string *p_self, const godot_array *p_splitters) \
- GDAPI_FUNC(godot_string_split_ints, godot_array, const godot_string *p_self, const godot_string *p_splitter) \
- GDAPI_FUNC(godot_string_split_ints_allows_empty, godot_array, const godot_string *p_self, const godot_string *p_splitter) \
- GDAPI_FUNC(godot_string_split_ints_mk, godot_array, const godot_string *p_self, const godot_array *p_splitters) \
- GDAPI_FUNC(godot_string_split_ints_mk_allows_empty, godot_array, const godot_string *p_self, const godot_array *p_splitters) \
- GDAPI_FUNC(godot_string_split_spaces, godot_array, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_char_lowercase, wchar_t, wchar_t p_char) \
- GDAPI_FUNC(godot_string_char_uppercase, wchar_t, wchar_t p_char) \
- GDAPI_FUNC(godot_string_to_lower, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_to_upper, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_get_basename, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_get_extension, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_left, godot_string, const godot_string *p_self, godot_int p_pos) \
- GDAPI_FUNC(godot_string_ord_at, wchar_t, const godot_string *p_self, godot_int p_idx) \
- GDAPI_FUNC(godot_string_plus_file, godot_string, const godot_string *p_self, const godot_string *p_file) \
- GDAPI_FUNC(godot_string_right, godot_string, const godot_string *p_self, godot_int p_pos) \
- GDAPI_FUNC(godot_string_strip_edges, godot_string, const godot_string *p_self, godot_bool p_left, godot_bool p_right) \
- GDAPI_FUNC(godot_string_strip_escapes, godot_string, const godot_string *p_self) \
- GDAPI_FUNC_VOID(godot_string_erase, godot_string *p_self, godot_int p_pos, godot_int p_chars) \
- GDAPI_FUNC_VOID(godot_string_ascii, godot_string *p_self, char *result) \
- GDAPI_FUNC_VOID(godot_string_ascii_extended, godot_string *p_self, char *result) \
- GDAPI_FUNC_VOID(godot_string_utf8, godot_string *p_self, char *result) \
- GDAPI_FUNC(godot_string_parse_utf8, godot_bool, godot_string *p_self, const char *p_utf8) \
- GDAPI_FUNC(godot_string_parse_utf8_with_len, godot_bool, godot_string *p_self, const char *p_utf8, godot_int p_len) \
- GDAPI_FUNC(godot_string_chars_to_utf8, godot_string, const char *p_utf8) \
- GDAPI_FUNC(godot_string_chars_to_utf8_with_len, godot_string, const char *p_utf8, godot_int p_len) \
- GDAPI_FUNC(godot_string_hash, uint32_t, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_hash64, uint64_t, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_hash_chars, uint32_t, const char *p_cstr) \
- GDAPI_FUNC(godot_string_hash_chars_with_len, uint32_t, const char *p_cstr, godot_int p_len) \
- GDAPI_FUNC(godot_string_hash_utf8_chars, uint32_t, const wchar_t *p_str) \
- GDAPI_FUNC(godot_string_hash_utf8_chars_with_len, uint32_t, const wchar_t *p_str, godot_int p_len) \
- GDAPI_FUNC(godot_string_md5_buffer, godot_pool_byte_array, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_md5_text, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_sha256_buffer, godot_pool_byte_array, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_sha256_text, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_empty, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_get_base_dir, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_get_file, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_humanize_size, godot_string, size_t p_size) \
- GDAPI_FUNC(godot_string_is_abs_path, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_rel_path, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_resource_file, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_path_to, godot_string, const godot_string *p_self, const godot_string *p_path) \
- GDAPI_FUNC(godot_string_path_to_file, godot_string, const godot_string *p_self, const godot_string *p_path) \
- GDAPI_FUNC(godot_string_simplify_path, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_c_escape, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_c_escape_multiline, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_c_unescape, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_http_escape, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_http_unescape, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_json_escape, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_word_wrap, godot_string, const godot_string *p_self, godot_int p_chars_per_line) \
- GDAPI_FUNC(godot_string_xml_escape, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_xml_escape_with_quotes, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_xml_unescape, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_percent_decode, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_percent_encode, godot_string, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_valid_float, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_valid_hex_number, godot_bool, const godot_string *p_self, godot_bool p_with_prefix) \
- GDAPI_FUNC(godot_string_is_valid_html_color, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_valid_identifier, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_valid_integer, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC(godot_string_is_valid_ip_address, godot_bool, const godot_string *p_self) \
- GDAPI_FUNC_VOID(godot_string_destroy, godot_string *p_self) \
- GDAPI_FUNC_VOID(godot_object_destroy, godot_object *p_o) \
- GDAPI_FUNC(godot_global_get_singleton, godot_object *, char *p_name) \
- GDAPI_FUNC(godot_get_stack_bottom, void *) \
- GDAPI_FUNC(godot_method_bind_get_method, godot_method_bind *, const char *p_classname, const char *p_methodname) \
- GDAPI_FUNC_VOID(godot_method_bind_ptrcall, godot_method_bind *p_method_bind, godot_object *p_instance, const void **p_args, void *p_ret) \
- GDAPI_FUNC(godot_method_bind_call, godot_variant, 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) \
- GDAPI_FUNC(godot_get_class_constructor, godot_class_constructor, const char *p_classname) \
- GDAPI_FUNC(godot_get_global_constants, godot_dictionary) \
- GDAPI_FUNC(godot_alloc, void *, int p_bytes) \
- GDAPI_FUNC(godot_realloc, void *, void *p_ptr, int p_bytes) \
- GDAPI_FUNC_VOID(godot_free, void *p_ptr) \
- GDAPI_FUNC_VOID(godot_print_error, const char *p_description, const char *p_function, const char *p_file, int p_line) \
- GDAPI_FUNC_VOID(godot_print_warning, const char *p_description, const char *p_function, const char *p_file, int p_line) \
- GDAPI_FUNC_VOID(godot_print, const godot_string *p_message) \
- GDAPI_FUNC_VOID(godot_nativescript_register_class, void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) \
- GDAPI_FUNC_VOID(godot_nativescript_register_tool_class, void *p_gdnative_handle, const char *p_name, const char *p_base, godot_instance_create_func p_create_func, godot_instance_destroy_func p_destroy_func) \
- GDAPI_FUNC_VOID(godot_nativescript_register_method, void *p_gdnative_handle, const char *p_name, const char *p_function_name, godot_method_attributes p_attr, godot_instance_method p_method) \
- GDAPI_FUNC_VOID(godot_nativescript_register_property, void *p_gdnative_handle, const char *p_name, const char *p_path, godot_property_attributes *p_attr, godot_property_set_func p_set_func, godot_property_get_func p_get_func) \
- GDAPI_FUNC_VOID(godot_nativescript_register_signal, void *p_gdnative_handle, const char *p_name, const godot_signal *p_signal) \
- GDAPI_FUNC(godot_nativescript_get_userdata, void *, godot_object *p_instance)
-
-#define GDAPI_FUNC(name, ret_type, ...) \
- ret_type (*name)(__VA_ARGS__);
-#define GDAPI_FUNC_VOID(name, ...) \
- void (*name)(__VA_ARGS__);
-
-typedef struct godot_gdnative_api_struct {
- GODOT_GDNATIVE_API_FUNCTIONS
-} godot_gdnative_api_struct;
-
-#undef GDAPI_FUNC
-#undef GDAPI_FUNC_VOID
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // GODOT_GDNATIVE_API_STRUCT_H
diff --git a/modules/gdnative/include/nativearvr/godot_nativearvr.h b/modules/gdnative/include/nativearvr/godot_nativearvr.h
new file mode 100644
index 0000000000..a4f4d6a9f1
--- /dev/null
+++ b/modules/gdnative/include/nativearvr/godot_nativearvr.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* godot_nativearvr.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GODOT_NATIVEARVR_H
+#define GODOT_NATIVEARVR_H
+
+#include <gdnative/gdnative.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ void *(*constructor)(godot_object *);
+ void (*destructor)(void *);
+ godot_string (*get_name)(const void *);
+ godot_int (*get_capabilities)(const void *);
+ godot_bool (*get_anchor_detection_is_enabled)(const void *);
+ void (*set_anchor_detection_is_enabled)(void *, godot_bool);
+ godot_bool (*is_stereo)(const void *);
+ godot_bool (*is_initialized)(const void *);
+ godot_bool (*initialize)(void *);
+ void (*uninitialize)(void *);
+ godot_vector2 (*get_recommended_render_targetsize)(const void *);
+ godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *);
+ void (*fill_projection_for_eye)(void *, godot_real *, godot_int, godot_real, godot_real, godot_real);
+ void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
+ void (*process)(void *);
+} godot_arvr_interface_gdnative;
+
+void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface);
+
+// helper functions to access ARVRServer data
+godot_real GDAPI godot_arvr_get_worldscale();
+godot_transform GDAPI godot_arvr_get_reference_frame();
+
+// helper functions for rendering
+void GDAPI godot_arvr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect);
+godot_int GDAPI godot_arvr_get_texid(godot_rid *p_render_target);
+
+// helper functions for updating ARVR controllers
+godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
+void GDAPI godot_arvr_remove_controller(godot_int p_controller_id);
+void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
+void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed);
+void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative);
+godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !GODOT_NATIVEARVR_H */
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index 96f213ead7..8baff0fff9 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -36,42 +36,6 @@
extern "C" {
#endif
-#ifdef GDAPI_BUILT_IN
-#define GDAPI_EXPORT
-#endif
-
-#ifdef _WIN32
-#if defined(GDAPI_EXPORT)
-#define GDCALLINGCONV
-#define GDAPI __declspec(dllexport) GDCALLINGCONV
-#else
-#define GDCALLINGCONV
-#define GDAPI __declspec(dllimport) GDCALLINGCONV
-#endif
-#elif defined(__APPLE__)
-#include "TargetConditionals.h"
-#if TARGET_OS_IPHONE
-#define GDCALLINGCONV
-#define GDAPI
-#elif TARGET_OS_MAC
-#define GDCALLINGCONV __attribute__((sysv_abi))
-#define GDAPI GDCALLINGCONV
-#endif
-#else
-#define GDCALLINGCONV __attribute__((sysv_abi, visibility("default")))
-#define GDAPI GDCALLINGCONV
-#endif
-
-// This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!!
-#ifdef _WIN32
-#define GDN_EXPORT __declspec(dllexport)
-#else
-#define GDN_EXPORT
-#endif
-
-#include <stdbool.h>
-#include <stdint.h>
-
typedef enum {
GODOT_METHOD_RPC_MODE_DISABLED,
GODOT_METHOD_RPC_MODE_REMOTE,
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
new file mode 100644
index 0000000000..d1c210529c
--- /dev/null
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -0,0 +1,171 @@
+/*************************************************************************/
+/* godot_nativescript.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_PLUGINSCRIPT_H
+#define GODOT_PLUGINSCRIPT_H
+
+#include <gdnative/gdnative.h>
+#include <nativescript/godot_nativescript.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void godot_pluginscript_instance_data;
+typedef void godot_pluginscript_script_data;
+typedef void godot_pluginscript_language_data;
+
+// --- Instance ---
+
+// TODO: use godot_string_name for faster lookup ?
+typedef struct {
+ godot_pluginscript_instance_data *(*init)(godot_pluginscript_script_data *p_data, godot_object *p_owner);
+ void (*finish)(godot_pluginscript_instance_data *p_data);
+
+ godot_bool (*set_prop)(godot_pluginscript_instance_data *p_data, const godot_string *p_name, const godot_variant *p_value);
+ godot_bool (*get_prop)(godot_pluginscript_instance_data *p_data, const godot_string *p_name, godot_variant *r_ret);
+
+ godot_variant (*call_method)(godot_pluginscript_instance_data *p_data,
+ const godot_string_name *p_method, const godot_variant **p_args,
+ int p_argcount, godot_variant_call_error *r_error);
+
+ void (*notification)(godot_pluginscript_instance_data *p_data, int p_notification);
+ // TODO: could this rpc mode stuff be moved to the godot_pluginscript_script_manifest ?
+ godot_method_rpc_mode (*get_rpc_mode)(godot_pluginscript_instance_data *p_data, const godot_string *p_method);
+ godot_method_rpc_mode (*get_rset_mode)(godot_pluginscript_instance_data *p_data, const godot_string *p_variable);
+
+ //this is used by script languages that keep a reference counter of their own
+ //you can make make Ref<> not die when it reaches zero, so deleting the reference
+ //depends entirely from the script.
+ // Note: You can set thoses function pointer to NULL if not needed.
+ void (*refcount_incremented)(godot_pluginscript_instance_data *p_data);
+ bool (*refcount_decremented)(godot_pluginscript_instance_data *p_data); // return true if it can die
+} godot_pluginscript_instance_desc;
+
+// --- Script ---
+
+typedef struct {
+ godot_pluginscript_script_data *data;
+ godot_string_name name;
+ godot_bool is_tool;
+ godot_string_name base;
+
+ // Member lines format: {<string>: <int>}
+ godot_dictionary member_lines;
+ // Method info dictionary format
+ // {
+ // name: <string>
+ // args: [<dict:property>]
+ // default_args: [<variant>]
+ // return: <dict:property>
+ // flags: <int>
+ // rpc_mode: <int:godot_method_rpc_mode>
+ // }
+ godot_array methods;
+ // Same format than for methods
+ godot_array signals;
+ // Property info dictionary format
+ // {
+ // name: <string>
+ // type: <int:godot_variant_type>
+ // hint: <int:godot_property_hint>
+ // hint_string: <string>
+ // usage: <int:godot_property_usage_flags>
+ // default_value: <variant>
+ // rset_mode: <int:godot_method_rpc_mode>
+ // }
+ godot_array properties;
+} godot_pluginscript_script_manifest;
+
+typedef struct {
+ godot_pluginscript_script_manifest (*init)(godot_pluginscript_language_data *p_data, const godot_string *p_path, const godot_string *p_source, godot_error *r_error);
+ void (*finish)(godot_pluginscript_script_data *p_data);
+ godot_pluginscript_instance_desc instance_desc;
+} godot_pluginscript_script_desc;
+
+// --- Language ---
+
+typedef struct {
+ godot_string_name signature;
+ godot_int call_count;
+ godot_int total_time; // In microseconds
+ godot_int self_time; // In microseconds
+} godot_pluginscript_profiling_data;
+
+typedef struct {
+ const char *name;
+ const char *type;
+ const char *extension;
+ const char **recognized_extensions; // NULL terminated array
+ godot_pluginscript_language_data *(*init)();
+ void (*finish)(godot_pluginscript_language_data *p_data);
+ const char **reserved_words; // NULL terminated array
+ const char **comment_delimiters; // NULL terminated array
+ const char **string_delimiters; // NULL terminated array
+ godot_bool has_named_classes;
+ godot_bool supports_builtin_mode;
+
+ godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name);
+ godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_pool_string_array *r_functions);
+ int (*find_function)(godot_pluginscript_language_data *p_data, const godot_string *p_function, const godot_string *p_code); // Can be NULL
+ godot_string (*make_function)(godot_pluginscript_language_data *p_data, const godot_string *p_class, const godot_string *p_name, const godot_pool_string_array *p_args);
+ godot_error (*complete_code)(godot_pluginscript_language_data *p_data, const godot_string *p_code, const godot_string *p_base_path, godot_object *p_owner, godot_array *r_options, godot_bool *r_force, godot_string *r_call_hint);
+ void (*auto_indent_code)(godot_pluginscript_language_data *p_data, godot_string *p_code, int p_from_line, int p_to_line);
+
+ void (*add_global_constant)(godot_pluginscript_language_data *p_data, const godot_string *p_variable, const godot_variant *p_value);
+ godot_string (*debug_get_error)(godot_pluginscript_language_data *p_data);
+ int (*debug_get_stack_level_count)(godot_pluginscript_language_data *p_data);
+ int (*debug_get_stack_level_line)(godot_pluginscript_language_data *p_data, int p_level);
+ godot_string (*debug_get_stack_level_function)(godot_pluginscript_language_data *p_data, int p_level);
+ godot_string (*debug_get_stack_level_source)(godot_pluginscript_language_data *p_data, int p_level);
+ void (*debug_get_stack_level_locals)(godot_pluginscript_language_data *p_data, int p_level, godot_pool_string_array *p_locals, godot_array *p_values, int p_max_subitems, int p_max_depth);
+ void (*debug_get_stack_level_members)(godot_pluginscript_language_data *p_data, int p_level, godot_pool_string_array *p_members, godot_array *p_values, int p_max_subitems, int p_max_depth);
+ void (*debug_get_globals)(godot_pluginscript_language_data *p_data, godot_pool_string_array *p_locals, godot_array *p_values, int p_max_subitems, int p_max_depth);
+ godot_string (*debug_parse_stack_level_expression)(godot_pluginscript_language_data *p_data, int p_level, const godot_string *p_expression, int p_max_subitems, int p_max_depth);
+
+ // TODO: could this stuff be moved to the godot_pluginscript_language_desc ?
+ void (*get_public_functions)(godot_pluginscript_language_data *p_data, godot_array *r_functions);
+ void (*get_public_constants)(godot_pluginscript_language_data *p_data, godot_dictionary *r_constants);
+
+ void (*profiling_start)(godot_pluginscript_language_data *p_data);
+ void (*profiling_stop)(godot_pluginscript_language_data *p_data);
+ int (*profiling_get_accumulated_data)(godot_pluginscript_language_data *p_data, godot_pluginscript_profiling_data *r_info, int p_info_max);
+ int (*profiling_get_frame_data)(godot_pluginscript_language_data *p_data, godot_pluginscript_profiling_data *r_info, int p_info_max);
+ void (*profiling_frame)(godot_pluginscript_language_data *p_data);
+
+ godot_pluginscript_script_desc script_desc;
+} godot_pluginscript_language_desc;
+
+void GDAPI godot_pluginscript_register_language(const godot_pluginscript_language_desc *language_desc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GODOT_PLUGINSCRIPT_H
diff --git a/modules/gdnative/nativearvr/SCsub b/modules/gdnative/nativearvr/SCsub
new file mode 100644
index 0000000000..ecc5996108
--- /dev/null
+++ b/modules/gdnative/nativearvr/SCsub
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+import os
+import methods
+
+Import('env')
+Import('env_modules')
+
+env_arvr_gdnative = env_modules.Clone()
+
+env_arvr_gdnative.Append(CPPPATH=['#modules/gdnative/include/'])
+env_arvr_gdnative.add_source_files(env.modules_sources, '*.cpp')
+
diff --git a/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp b/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp
new file mode 100644
index 0000000000..e2a7019fa4
--- /dev/null
+++ b/modules/gdnative/nativearvr/arvr_interface_gdnative.cpp
@@ -0,0 +1,398 @@
+/*************************************************************************/
+/* arvr_interface_gdnative.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "arvr_interface_gdnative.h"
+#include "main/input_default.h"
+#include "servers/arvr/arvr_positional_tracker.h"
+#include "servers/visual/visual_server_global.h"
+
+ARVRInterfaceGDNative::ARVRInterfaceGDNative() {
+ // testing
+ printf("Construct gdnative interface\n");
+
+ // we won't have our data pointer until our library gets set
+ data = NULL;
+
+ interface = NULL;
+}
+
+ARVRInterfaceGDNative::~ARVRInterfaceGDNative() {
+ printf("Destruct gdnative interface\n");
+
+ if (is_initialized()) {
+ uninitialize();
+ };
+
+ // cleanup after ourselves
+ cleanup();
+}
+
+void ARVRInterfaceGDNative::cleanup() {
+ if (interface != NULL) {
+ interface->destructor(data);
+ data = NULL;
+ interface = NULL;
+ }
+}
+
+void ARVRInterfaceGDNative::set_interface(const godot_arvr_interface_gdnative *p_interface) {
+ // this should only be called once, just being paranoid..
+ if (interface) {
+ cleanup();
+ }
+
+ // bind to our interface
+ interface = p_interface;
+
+ // Now we do our constructing...
+ data = interface->constructor((godot_object *)this);
+}
+
+StringName ARVRInterfaceGDNative::get_name() const {
+
+ ERR_FAIL_COND_V(interface == NULL, StringName());
+
+ godot_string result = interface->get_name(data);
+
+ StringName name = *(String *)&result;
+
+ godot_string_destroy(&result);
+
+ return name;
+}
+
+int ARVRInterfaceGDNative::get_capabilities() const {
+ int capabilities;
+
+ ERR_FAIL_COND_V(interface == NULL, 0); // 0 = None
+
+ capabilities = interface->get_capabilities(data);
+
+ return capabilities;
+}
+
+bool ARVRInterfaceGDNative::get_anchor_detection_is_enabled() const {
+ bool enabled;
+
+ ERR_FAIL_COND_V(interface == NULL, false);
+
+ enabled = interface->get_anchor_detection_is_enabled(data);
+
+ return enabled;
+}
+
+void ARVRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) {
+
+ ERR_FAIL_COND(interface == NULL);
+
+ interface->set_anchor_detection_is_enabled(data, p_enable);
+}
+
+bool ARVRInterfaceGDNative::is_stereo() {
+ bool stereo;
+
+ ERR_FAIL_COND_V(interface == NULL, false);
+
+ stereo = interface->is_stereo(data);
+
+ return stereo;
+}
+
+bool ARVRInterfaceGDNative::is_initialized() {
+ bool initialized;
+
+ ERR_FAIL_COND_V(interface == NULL, false);
+
+ initialized = interface->is_initialized(data);
+
+ return initialized;
+}
+
+bool ARVRInterfaceGDNative::initialize() {
+ bool initialized;
+
+ ERR_FAIL_COND_V(interface == NULL, false);
+
+ initialized = interface->initialize(data);
+
+ if (initialized) {
+ // if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface
+
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ if ((arvr_server != NULL) && (arvr_server->get_primary_interface() == NULL)) {
+ arvr_server->set_primary_interface(this);
+ };
+ };
+
+ return initialized;
+}
+
+void ARVRInterfaceGDNative::uninitialize() {
+ ERR_FAIL_COND(interface == NULL);
+
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ if (arvr_server != NULL) {
+ // Whatever happens, make sure this is no longer our primary interface
+ arvr_server->clear_primary_interface_if(this);
+ }
+
+ interface->uninitialize(data);
+}
+
+Size2 ARVRInterfaceGDNative::get_recommended_render_targetsize() {
+
+ ERR_FAIL_COND_V(interface == NULL, Size2());
+
+ godot_vector2 result = interface->get_recommended_render_targetsize(data);
+ Vector2 *vec = (Vector2 *)&result;
+
+ return *vec;
+}
+
+Transform ARVRInterfaceGDNative::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+ Transform *ret;
+
+ ERR_FAIL_COND_V(interface == NULL, Transform());
+
+ godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform);
+
+ ret = (Transform *)&t;
+
+ return *ret;
+}
+
+CameraMatrix ARVRInterfaceGDNative::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+ CameraMatrix cm;
+
+ ERR_FAIL_COND_V(interface == NULL, CameraMatrix());
+
+ interface->fill_projection_for_eye(data, (godot_real *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far);
+
+ return cm;
+}
+
+void ARVRInterfaceGDNative::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
+
+ ERR_FAIL_COND(interface == NULL);
+
+ interface->commit_for_eye(data, (godot_int)p_eye, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
+}
+
+void ARVRInterfaceGDNative::process() {
+ ERR_FAIL_COND(interface == NULL);
+
+ interface->process(data);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// some helper callbacks
+
+extern "C" {
+
+void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface) {
+ Ref<ARVRInterfaceGDNative> new_interface;
+ new_interface.instance();
+ new_interface->set_interface((godot_arvr_interface_gdnative * const)p_interface);
+ ARVRServer::get_singleton()->add_interface(new_interface);
+}
+
+godot_real GDAPI godot_arvr_get_worldscale() {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, 1.0);
+
+ return arvr_server->get_world_scale();
+}
+
+godot_transform GDAPI godot_arvr_get_reference_frame() {
+ godot_transform reference_frame;
+ Transform *reference_frame_ptr = (Transform *)&reference_frame;
+
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ if (arvr_server != NULL) {
+ *reference_frame_ptr = arvr_server->get_reference_frame();
+ } else {
+ godot_transform_new_identity(&reference_frame);
+ }
+
+ return reference_frame;
+}
+
+void GDAPI godot_arvr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect) {
+ // blits out our texture as is, handy for preview display of one of the eyes that is already rendered with lens distortion on an external HMD
+ ARVRInterface::Eyes eye = (ARVRInterface::Eyes)p_eye;
+ RID *render_target = (RID *)p_render_target;
+ Rect2 screen_rect = *(Rect2 *)p_rect;
+
+ if (eye == ARVRInterface::EYE_LEFT) {
+ screen_rect.size.x /= 2.0;
+ } else if (p_eye == ARVRInterface::EYE_RIGHT) {
+ screen_rect.size.x /= 2.0;
+ screen_rect.position.x += screen_rect.size.x;
+ }
+
+ VSG::rasterizer->set_current_render_target(RID());
+ VSG::rasterizer->blit_render_target_to_screen(*render_target, screen_rect, 0);
+}
+
+godot_int GDAPI godot_arvr_get_texid(godot_rid *p_render_target) {
+ // In order to send off our textures to display on our hardware we need the opengl texture ID instead of the render target RID
+ // This is a handy function to expose that.
+ RID *render_target = (RID *)p_render_target;
+
+ RID eye_texture = VSG::storage->render_target_get_texture(*render_target);
+ uint32_t texid = VS::get_singleton()->texture_get_texid(eye_texture);
+
+ return texid;
+}
+
+godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, 0);
+
+ InputDefault *input = (InputDefault *)Input::get_singleton();
+ ERR_FAIL_NULL_V(input, 0);
+
+ ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
+ new_tracker->set_name(p_device_name);
+ new_tracker->set_type(ARVRServer::TRACKER_CONTROLLER);
+ if (p_hand == 1) {
+ new_tracker->set_hand(ARVRPositionalTracker::TRACKER_LEFT_HAND);
+ } else if (p_hand == 2) {
+ new_tracker->set_hand(ARVRPositionalTracker::TRACKER_RIGHT_HAND);
+ }
+
+ // also register as joystick...
+ int joyid = input->get_unused_joy_id();
+ if (joyid != -1) {
+ new_tracker->set_joy_id(joyid);
+ input->joy_connection_changed(joyid, true, p_device_name, "");
+ }
+
+ if (p_tracks_orientation) {
+ Basis orientation;
+ new_tracker->set_orientation(orientation);
+ }
+ if (p_tracks_position) {
+ Vector3 position;
+ new_tracker->set_position(position);
+ }
+
+ // add our tracker to our server and remember its pointer
+ arvr_server->add_tracker(new_tracker);
+
+ // note, this ID is only unique within controllers!
+ return new_tracker->get_tracker_id();
+}
+
+void GDAPI godot_arvr_remove_controller(godot_int p_controller_id) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
+ InputDefault *input = (InputDefault *)Input::get_singleton();
+ ERR_FAIL_NULL(input);
+
+ ARVRPositionalTracker *remove_tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (remove_tracker != NULL) {
+ // unset our joystick if applicable
+ int joyid = remove_tracker->get_joy_id();
+ if (joyid != -1) {
+ input->joy_connection_changed(joyid, false, "", "");
+ remove_tracker->set_joy_id(-1);
+ }
+
+ // remove our tracker from our server
+ arvr_server->remove_tracker(remove_tracker);
+ memdelete(remove_tracker);
+ }
+}
+
+void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
+ ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker != NULL) {
+ Transform *transform = (Transform *)p_transform;
+ if (p_tracks_orientation) {
+ tracker->set_orientation(transform->basis);
+ }
+ if (p_tracks_position) {
+ tracker->set_position(transform->origin);
+ }
+ }
+}
+
+void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
+ InputDefault *input = (InputDefault *)Input::get_singleton();
+ ERR_FAIL_NULL(input);
+
+ ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker != NULL) {
+ int joyid = tracker->get_joy_id();
+ if (joyid != -1) {
+ input->joy_button(joyid, p_button, p_is_pressed);
+ }
+ }
+}
+
+void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL(arvr_server);
+
+ InputDefault *input = (InputDefault *)Input::get_singleton();
+ ERR_FAIL_NULL(input);
+
+ ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker != NULL) {
+ int joyid = tracker->get_joy_id();
+ if (joyid != -1) {
+ InputDefault::JoyAxis jx;
+ jx.min = p_can_be_negative ? -1 : 0;
+ jx.value = p_value;
+ input->joy_axis(joyid, p_axis, jx);
+ }
+ }
+}
+
+godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, 0.0);
+
+ ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker != NULL) {
+ return tracker->get_rumble();
+ }
+
+ return 0.0;
+}
+}
diff --git a/modules/gdnative/nativearvr/arvr_interface_gdnative.h b/modules/gdnative/nativearvr/arvr_interface_gdnative.h
new file mode 100644
index 0000000000..e45b51e070
--- /dev/null
+++ b/modules/gdnative/nativearvr/arvr_interface_gdnative.h
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* arvr_interface_gdnative.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef ARVR_INTERFACE_GDNATIVE_H
+#define ARVR_INTERFACE_GDNATIVE_H
+
+#include "modules/gdnative/gdnative.h"
+#include "servers/arvr/arvr_interface.h"
+
+/**
+ @authors Hinsbart & Karroffel & Mux213
+
+ This subclass of our AR/VR interface forms a bridge to GDNative.
+*/
+
+class ARVRInterfaceGDNative : public ARVRInterface {
+ GDCLASS(ARVRInterfaceGDNative, ARVRInterface)
+
+ void cleanup();
+
+protected:
+ const godot_arvr_interface_gdnative *interface;
+ void *data;
+
+public:
+ /** general interface information **/
+ ARVRInterfaceGDNative();
+ ~ARVRInterfaceGDNative();
+
+ void set_interface(const godot_arvr_interface_gdnative *p_interface);
+
+ virtual StringName get_name() const;
+ virtual int get_capabilities() const;
+
+ virtual bool is_initialized();
+ virtual bool initialize();
+ virtual void uninitialize();
+
+ /** specific to AR **/
+ virtual bool get_anchor_detection_is_enabled() const;
+ virtual void set_anchor_detection_is_enabled(bool p_enable);
+
+ /** rendering and internal **/
+ virtual Size2 get_recommended_render_targetsize();
+ virtual bool is_stereo();
+ virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
+
+ // we expose a PoolVector<float> version of this function to GDNative
+ PoolVector<float> _get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+
+ // and a CameraMatrix version to ARVRServer
+ virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+
+ virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
+
+ virtual void process();
+};
+
+#endif // ARVR_INTERFACE_GDNATIVE_H
diff --git a/modules/gdnative/nativearvr/config.py b/modules/gdnative/nativearvr/config.py
new file mode 100644
index 0000000000..4d1bdfe4d1
--- /dev/null
+++ b/modules/gdnative/nativearvr/config.py
@@ -0,0 +1,5 @@
+def can_build(platform):
+ return True
+
+def configure(env):
+ pass
diff --git a/modules/gdnative/nativearvr/register_types.cpp b/modules/gdnative/nativearvr/register_types.cpp
new file mode 100644
index 0000000000..c7d7847a21
--- /dev/null
+++ b/modules/gdnative/nativearvr/register_types.cpp
@@ -0,0 +1,39 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "register_types.h"
+#include "arvr_interface_gdnative.h"
+
+void register_nativearvr_types() {
+ ClassDB::register_class<ARVRInterfaceGDNative>();
+}
+
+void unregister_nativearvr_types() {
+}
diff --git a/modules/gdnative/nativearvr/register_types.h b/modules/gdnative/nativearvr/register_types.h
new file mode 100644
index 0000000000..5e7557c7e9
--- /dev/null
+++ b/modules/gdnative/nativearvr/register_types.h
@@ -0,0 +1,32 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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_nativearvr_types();
+void unregister_nativearvr_types();
diff --git a/modules/gdnative/nativescript/SCsub b/modules/gdnative/nativescript/SCsub
index e980e40e8e..ee3b9c351d 100644
--- a/modules/gdnative/nativescript/SCsub
+++ b/modules/gdnative/nativescript/SCsub
@@ -4,7 +4,9 @@ Import('env')
mod_env = env.Clone()
mod_env.add_source_files(env.modules_sources, "*.cpp")
-mod_env.Append(CPPPATH='#modules/gdnative')
mod_env.Append(CPPFLAGS=['-DGDAPI_BUILT_IN'])
+if "platform" in env and env["platform"] in ["x11", "iphone"]:
+ env.Append(LINKFLAGS=["-rdynamic"])
+
Export('mod_env')
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index fdd5a2ea19..63fb71feb6 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -31,7 +31,7 @@
#ifdef TOOLS_ENABLED
-#include "class_db.h"
+#include "core/class_db.h"
#include "core/global_constants.h"
#include "core/pair.h"
#include "core/project_settings.h"
@@ -80,6 +80,7 @@ struct PropertyAPI {
String getter;
String setter;
String type;
+ int index;
};
struct ConstantAPI {
@@ -259,6 +260,8 @@ List<ClassAPI> generate_c_api_classes() {
property_api.type = get_type_name(p->get());
}
+ property_api.index = ClassDB::get_property_index(class_name, p->get().name);
+
if (!property_api.setter.empty() || !property_api.getter.empty()) {
class_api.properties.push_back(property_api);
}
@@ -395,7 +398,8 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back("\t\t\t\t\"name\": \"" + e->get().name + "\",\n");
source.push_back("\t\t\t\t\"type\": \"" + e->get().type + "\",\n");
source.push_back("\t\t\t\t\"getter\": \"" + e->get().getter + "\",\n");
- source.push_back("\t\t\t\t\"setter\": \"" + e->get().setter + "\"\n");
+ source.push_back("\t\t\t\t\"setter\": \"" + e->get().setter + "\",\n");
+ source.push_back(String("\t\t\t\t\"index\": ") + itos(e->get().index) + "\n");
source.push_back(String("\t\t\t}") + (e->next() ? "," : "") + "\n");
}
source.push_back("\t\t],\n");
diff --git a/modules/gdnative/nativescript/api_generator.h b/modules/gdnative/nativescript/api_generator.h
index 56c2d786e6..a8e2eaf0bf 100644
--- a/modules/gdnative/nativescript/api_generator.h
+++ b/modules/gdnative/nativescript/api_generator.h
@@ -30,8 +30,8 @@
#ifndef API_GENERATOR_H
#define API_GENERATOR_H
+#include "core/typedefs.h"
#include "core/ustring.h"
-#include "typedefs.h"
Error generate_c_api(const String &p_path);
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index b9bd65af53..c1df7def2e 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -31,11 +31,11 @@
#include "gdnative/gdnative.h"
-#include "global_constants.h"
+#include "core/global_constants.h"
+#include "core/project_settings.h"
#include "io/file_access_encrypted.h"
#include "os/file_access.h"
#include "os/os.h"
-#include "project_settings.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/scene_format_text.h"
@@ -137,7 +137,6 @@ bool NativeScript::can_instance() const {
#endif
}
-// TODO(karroffel): implement this
Ref<Script> NativeScript::get_base_script() const {
NativeScriptDesc *script_data = get_script_desc();
@@ -271,10 +270,6 @@ bool NativeScript::is_tool() const {
return false;
}
-String NativeScript::get_node_type() const {
- return ""; // NOTE(karroffel): uhm?
-}
-
ScriptLanguage *NativeScript::get_language() const {
return NativeScriptLanguage::get_singleton();
}
@@ -909,6 +904,9 @@ Script *NativeScriptLanguage::create_script() const {
bool NativeScriptLanguage::has_named_classes() const {
return true;
}
+bool NativeScriptLanguage::supports_builtin_mode() const {
+ return true;
+}
int NativeScriptLanguage::find_function(const String &p_function, const String &p_code) const {
return -1;
}
@@ -1010,17 +1008,15 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) {
if (!library_script_users.has(lib_path))
library_script_users.insert(lib_path, Set<NativeScript *>());
- void *args[1] = {
- (void *)&lib_path
- };
+ void *proc_ptr;
- // here the library registers all the classes and stuff.
- gdn->call_native_raw(_init_call_type,
- _init_call_name,
- NULL,
- 1,
- args,
- NULL);
+ Error err = gdn->get_symbol(_init_call_name, proc_ptr);
+
+ if (err != OK) {
+ ERR_PRINT(String("No " + _init_call_name + " in \"" + lib_path + "\" found").utf8().get_data());
+ } else {
+ ((void (*)(godot_string *))proc_ptr)((godot_string *)&lib_path);
+ }
} else {
// already initialized. Nice.
}
@@ -1053,13 +1049,13 @@ void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
// library_gdnatives is modified only from the main thread, so it's safe not to use mutex here
for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) {
if (L->get()->is_initialized()) {
- L->get()->call_native_raw(
- _noarg_call_type,
- name,
- NULL,
- 0,
- NULL,
- NULL);
+
+ void *proc_ptr;
+ Error err = L->get()->get_symbol(name, proc_ptr);
+
+ if (!err) {
+ ((void (*)())proc_ptr)();
+ }
}
}
}
@@ -1142,12 +1138,14 @@ void NativeReloadNode::_notification(int p_what) {
};
// here the library registers all the classes and stuff.
- L->get()->call_native_raw(NSL->_init_call_type,
- NSL->_init_call_name,
- NULL,
- 1,
- args,
- NULL);
+
+ void *proc_ptr;
+ Error err = L->get()->get_symbol("godot_nativescript_init", proc_ptr);
+ if (err != OK) {
+ ERR_PRINT(String("No godot_nativescript_init in \"" + L->key() + "\" found").utf8().get_data());
+ } else {
+ ((void (*)(void *))proc_ptr)((void *)&L->key());
+ }
for (Map<String, Set<NativeScript *> >::Element *U = NSL->library_script_users.front(); U; U = U->next()) {
for (Set<NativeScript *>::Element *S = U->get().front(); S; S = S->next()) {
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index bc7e850d3e..e8fc9e6880 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -30,14 +30,14 @@
#ifndef NATIVE_SCRIPT_H
#define NATIVE_SCRIPT_H
+#include "core/resource.h"
+#include "core/script_language.h"
+#include "core/self_list.h"
#include "io/resource_loader.h"
#include "io/resource_saver.h"
#include "ordered_hash_map.h"
#include "os/thread_safe.h"
-#include "resource.h"
#include "scene/main/node.h"
-#include "script_language.h"
-#include "self_list.h"
#include "modules/gdnative/gdnative.h"
#include <nativescript/godot_nativescript.h>
@@ -142,8 +142,6 @@ public:
virtual bool is_tool() const;
- virtual String get_node_type() const;
-
virtual ScriptLanguage *get_language() const;
virtual bool has_script_signal(const StringName &p_signal) const;
@@ -271,6 +269,7 @@ public:
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() 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 PoolStringArray &p_args) const;
virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp
index b846710ab8..d734bba810 100644
--- a/modules/gdnative/nativescript/register_types.cpp
+++ b/modules/gdnative/nativescript/register_types.cpp
@@ -38,53 +38,6 @@
NativeScriptLanguage *native_script_language;
-typedef void (*native_script_init_fn)(void *);
-
-void init_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) {
- if (p_handle == NULL) {
- ERR_PRINT("No valid library handle, can't call nativescript init procedure");
- return;
- }
-
- void *library_proc;
- Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
- p_handle,
- *(String *)p_proc_name,
- library_proc,
- true); // we print our own message
- if (err != OK) {
- ERR_PRINT((String("GDNative procedure \"" + *(String *)p_proc_name) + "\" does not exists and can't be called").utf8().get_data());
- return;
- }
-
- native_script_init_fn fn = (native_script_init_fn)library_proc;
-
- fn(args[0]);
-}
-
-typedef void (*native_script_empty_callback)();
-
-void noarg_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) {
- if (p_handle == NULL) {
- ERR_PRINT("No valid library handle, can't call nativescript callback");
- return;
- }
-
- void *library_proc;
- Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
- p_handle,
- *(String *)p_proc_name,
- library_proc,
- true);
- if (err != OK) {
- // it's fine if thread callbacks are not present in the library.
- return;
- }
-
- native_script_empty_callback fn = (native_script_empty_callback)library_proc;
- fn();
-}
-
ResourceFormatLoaderNativeScript *resource_loader_gdns = NULL;
ResourceFormatSaverNativeScript *resource_saver_gdns = NULL;
@@ -95,9 +48,6 @@ void register_nativescript_types() {
ScriptServer::register_language(native_script_language);
- GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_init_call_type, init_call_cb);
- GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_noarg_call_type, noarg_call_cb);
-
resource_saver_gdns = memnew(ResourceFormatSaverNativeScript);
ResourceSaver::add_resource_format_saver(resource_saver_gdns);
diff --git a/modules/gdnative/pluginscript/SCsub b/modules/gdnative/pluginscript/SCsub
new file mode 100644
index 0000000000..2031a4236b
--- /dev/null
+++ b/modules/gdnative/pluginscript/SCsub
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+env_pluginscript = env_modules.Clone()
+
+env_pluginscript.Append(CPPPATH=['#modules/gdnative/include/'])
+env_pluginscript.add_source_files(env.modules_sources, '*.cpp')
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
new file mode 100644
index 0000000000..8f01350826
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -0,0 +1,181 @@
+/*************************************************************************/
+/* pluginscript_instance.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+// Godot imports
+#include "core/os/os.h"
+#include "core/variant.h"
+// PluginScript imports
+#include "pluginscript_instance.h"
+#include "pluginscript_language.h"
+#include "pluginscript_script.h"
+
+bool PluginScriptInstance::set(const StringName &p_name, const Variant &p_value) {
+ String name = String(p_name);
+ return _desc->set_prop(_data, (const godot_string *)&name, (const godot_variant *)&p_value);
+}
+
+bool PluginScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
+ String name = String(p_name);
+ return _desc->get_prop(_data, (const godot_string *)&name, (godot_variant *)&r_ret);
+}
+
+Ref<Script> PluginScriptInstance::get_script() const {
+ return _script;
+}
+
+ScriptLanguage *PluginScriptInstance::get_language() {
+ return _script->get_language();
+}
+
+Variant::Type PluginScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
+ if (!_script->has_property(p_name)) {
+ if (r_is_valid) {
+ *r_is_valid = false;
+ }
+ return Variant::NIL;
+ }
+ if (r_is_valid) {
+ *r_is_valid = true;
+ }
+ return _script->get_property_info(p_name).type;
+}
+
+void PluginScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
+ _script->get_script_property_list(p_properties);
+}
+
+void PluginScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
+ _script->get_script_method_list(p_list);
+}
+
+bool PluginScriptInstance::has_method(const StringName &p_method) const {
+ return _script->has_method(p_method);
+}
+
+Variant PluginScriptInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+ // TODO: optimize when calling a Godot method from Godot to avoid param conversion ?
+ godot_variant ret = _desc->call_method(
+ _data, (godot_string_name *)&p_method, (const godot_variant **)p_args,
+ p_argcount, (godot_variant_call_error *)&r_error);
+ Variant *var_ret = (Variant *)&ret;
+ return *var_ret;
+}
+
+#if 0 // TODO: Don't rely on default implementations provided by ScriptInstance ?
+void PluginScriptInstance::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount) {
+
+#if 0
+ PluginScript *sptr=script.ptr();
+ Variant::CallError ce;
+
+ while(sptr) {
+ Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method);
+ if (E) {
+ E->get()->call(this,p_args,p_argcount,ce);
+ }
+ sptr = sptr->_base;
+ }
+#endif
+
+}
+
+#if 0
+void PluginScriptInstance::_ml_call_reversed(PluginScript *sptr,const StringName& p_method,const Variant** p_args,int p_argcount) {
+
+ if (sptr->_base)
+ _ml_call_reversed(sptr->_base,p_method,p_args,p_argcount);
+
+ Variant::CallError ce;
+
+ Map<StringName,GDFunction*>::Element *E = sptr->member_functions.find(p_method);
+ if (E) {
+ E->get()->call(this,p_args,p_argcount,ce);
+ }
+
+}
+#endif
+
+
+void PluginScriptInstance::call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount) {
+
+#if 0
+ if (script.ptr()) {
+ _ml_call_reversed(script.ptr(),p_method,p_args,p_argcount);
+ }
+#endif
+}
+#endif // Multilevel stuff
+
+void PluginScriptInstance::notification(int p_notification) {
+ _desc->notification(_data, p_notification);
+}
+
+ScriptInstance::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const {
+ return _script->get_rpc_mode(p_method);
+}
+
+ScriptInstance::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const {
+ return _script->get_rset_mode(p_variable);
+}
+
+void PluginScriptInstance::refcount_incremented() {
+ if (_desc->refcount_decremented) {
+ _desc->refcount_incremented(_data);
+ }
+}
+
+bool PluginScriptInstance::refcount_decremented() {
+ // Return true if it can die
+ if (_desc->refcount_decremented) {
+ return _desc->refcount_decremented(_data);
+ }
+ return true;
+}
+
+PluginScriptInstance::PluginScriptInstance() {
+}
+
+bool PluginScriptInstance::init(PluginScript *p_script, Object *p_owner) {
+ _owner = p_owner;
+ _owner_variant = Variant(p_owner);
+ _script = Ref<PluginScript>(p_script);
+ _desc = &p_script->_desc->instance_desc;
+ _data = _desc->init(p_script->_data, (godot_object *)p_owner);
+ ERR_FAIL_COND_V(_data == NULL, false);
+ p_owner->set_script_instance(this);
+ return true;
+}
+
+PluginScriptInstance::~PluginScriptInstance() {
+ _desc->finish(_data);
+ _script->_language->lock();
+ _script->_instances.erase(_owner);
+ _script->_language->unlock();
+}
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
new file mode 100644
index 0000000000..68696b4417
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* pluginscript_instance.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PLUGINSCRIPT_INSTANCE_H
+#define PLUGINSCRIPT_INSTANCE_H
+
+// Godot imports
+#include "core/script_language.h"
+// PluginScript imports
+#include <pluginscript/godot_pluginscript.h>
+
+class PluginScript;
+
+class PluginScriptInstance : public ScriptInstance {
+ friend class PluginScript;
+
+private:
+ Ref<PluginScript> _script;
+ Object *_owner;
+ Variant _owner_variant;
+ godot_pluginscript_instance_data *_data;
+ const godot_pluginscript_instance_desc *_desc;
+
+public:
+ _FORCE_INLINE_ Object *get_owner() { return _owner; }
+
+ virtual bool set(const StringName &p_name, const Variant &p_value);
+ virtual bool get(const StringName &p_name, Variant &r_ret) const;
+ virtual void get_property_list(List<PropertyInfo> *p_properties) const;
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const;
+
+ virtual void get_method_list(List<MethodInfo> *p_list) const;
+ virtual bool has_method(const StringName &p_method) const;
+
+ virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+#if 0
+ // Rely on default implementations provided by ScriptInstance for the moment.
+ // Note that multilevel call could be removed in 3.0 release, so stay tunned
+ // (see https://godotengine.org/qa/9244/can-override-the-_ready-and-_process-functions-child-classes)
+ virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount);
+ virtual void call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount);
+#endif
+
+ virtual void notification(int p_notification);
+
+ virtual Ref<Script> get_script() const;
+
+ virtual ScriptLanguage *get_language();
+
+ void set_path(const String &p_path);
+
+ virtual RPCMode get_rpc_mode(const StringName &p_method) const;
+ virtual RPCMode get_rset_mode(const StringName &p_variable) const;
+
+ virtual void refcount_incremented();
+ virtual bool refcount_decremented();
+
+ PluginScriptInstance();
+ bool init(PluginScript *p_script, Object *p_owner);
+ virtual ~PluginScriptInstance();
+};
+
+#endif // PLUGINSCRIPT_INSTANCE_H
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
new file mode 100644
index 0000000000..40feb5ae43
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -0,0 +1,435 @@
+/*************************************************************************/
+/* pluginscript_language.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+// Godot imports
+#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"
+
+String PluginScriptLanguage::get_name() const {
+ return String(_desc.name);
+}
+
+void PluginScriptLanguage::init() {
+ _data = _desc.init();
+}
+
+String PluginScriptLanguage::get_type() const {
+ return String(_desc.type);
+}
+
+String PluginScriptLanguage::get_extension() const {
+ return String(_desc.extension);
+}
+
+Error PluginScriptLanguage::execute_file(const String &p_path) {
+ // TODO: pretty sure this method is totally deprecated and should be removed...
+ return OK;
+}
+
+void PluginScriptLanguage::finish() {
+ _desc.finish(_data);
+}
+
+/* EDITOR FUNCTIONS */
+
+void PluginScriptLanguage::get_reserved_words(List<String> *p_words) const {
+ if (_desc.reserved_words) {
+ const char **w = _desc.reserved_words;
+ while (*w) {
+ p_words->push_back(*w);
+ w++;
+ }
+ }
+}
+
+void PluginScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
+ if (_desc.comment_delimiters) {
+ const char **w = _desc.comment_delimiters;
+ while (*w) {
+ p_delimiters->push_back(*w);
+ w++;
+ }
+ }
+}
+
+void PluginScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
+ if (_desc.string_delimiters) {
+ const char **w = _desc.string_delimiters;
+ while (*w) {
+ p_delimiters->push_back(*w);
+ w++;
+ }
+ }
+}
+
+Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
+ Script *ns = create_script();
+ Ref<Script> script = Ref<Script>(ns);
+ if (_desc.get_template_source_code) {
+ godot_string src = _desc.get_template_source_code(_data, (godot_string *)&p_class_name, (godot_string *)&p_base_class_name);
+ script->set_source_code(*(String *)&src);
+ }
+ return script;
+}
+
+bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const {
+ PoolStringArray functions;
+ if (_desc.validate) {
+ bool ret = _desc.validate(
+ _data,
+ (godot_string *)&p_script,
+ &r_line_error,
+ &r_col_error,
+ (godot_string *)&r_test_error,
+ (godot_string *)&p_path,
+ (godot_pool_string_array *)&functions);
+ for (int i = 0; i < functions.size(); i++) {
+ r_functions->push_back(functions[i]);
+ }
+ return ret;
+ }
+ return true;
+}
+
+Script *PluginScriptLanguage::create_script() const {
+ PluginScript *script = memnew(PluginScript());
+ // I'm hurting kittens doing this I guess...
+ script->init(const_cast<PluginScriptLanguage *>(this));
+ return script;
+}
+
+bool PluginScriptLanguage::has_named_classes() const {
+ return _desc.has_named_classes;
+}
+
+bool PluginScriptLanguage::supports_builtin_mode() const {
+ return _desc.supports_builtin_mode;
+}
+
+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);
+ }
+ return -1;
+}
+
+String PluginScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const {
+ if (_desc.make_function) {
+ godot_string tmp = _desc.make_function(_data, (godot_string *)&p_class, (godot_string *)&p_name, (godot_pool_string_array *)&p_args);
+ String ret = *(String *)&tmp;
+ godot_string_destroy(&tmp);
+ return ret;
+ }
+ return String();
+}
+
+Error PluginScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint) {
+ if (_desc.complete_code) {
+ Array options;
+ godot_error tmp = _desc.complete_code(
+ _data,
+ (godot_string *)&p_code,
+ (godot_string *)&p_base_path,
+ (godot_object *)p_owner,
+ (godot_array *)&options,
+ &r_force,
+ (godot_string *)&r_call_hint);
+ for (int i = 0; i < options.size(); i++) {
+ r_options->push_back(String(options[i]));
+ }
+ Error err = *(Error *)tmp;
+ return err;
+ }
+ return ERR_UNAVAILABLE;
+}
+
+void PluginScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {
+ if (_desc.auto_indent_code) {
+ _desc.auto_indent_code(_data, (godot_string *)&p_code, p_from_line, p_to_line);
+ }
+ return;
+}
+
+void PluginScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
+ const String variable = String(p_variable);
+ _desc.add_global_constant(_data, (godot_string *)&variable, (godot_variant *)&p_value);
+}
+
+/* LOADER FUNCTIONS */
+
+void PluginScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
+ for (int i = 0; _desc.recognized_extensions[i]; ++i) {
+ p_extensions->push_back(String(_desc.recognized_extensions[i]));
+ }
+}
+
+void PluginScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
+ // TODO: provid this statically in `godot_pluginscript_language_desc` ?
+ if (_desc.get_public_functions) {
+ Array functions;
+ _desc.get_public_functions(_data, (godot_array *)&functions);
+ for (int i = 0; i < functions.size(); i++) {
+ MethodInfo mi = MethodInfo::from_dict(functions[i]);
+ p_functions->push_back(mi);
+ }
+ }
+}
+
+void PluginScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_constants) const {
+ // TODO: provid this statically in `godot_pluginscript_language_desc` ?
+ if (_desc.get_public_constants) {
+ Dictionary constants;
+ _desc.get_public_constants(_data, (godot_dictionary *)&constants);
+ for (const Variant *key = constants.next(); key; key = constants.next(key)) {
+ Variant value = constants[key];
+ p_constants->push_back(Pair<String, Variant>(*key, value));
+ }
+ }
+}
+
+void PluginScriptLanguage::profiling_start() {
+#ifdef DEBUG_ENABLED
+ if (_desc.profiling_start) {
+ lock();
+ _desc.profiling_start(_data);
+ unlock();
+ }
+#endif
+}
+
+void PluginScriptLanguage::profiling_stop() {
+#ifdef DEBUG_ENABLED
+ if (_desc.profiling_stop) {
+ lock();
+ _desc.profiling_stop(_data);
+ unlock();
+ }
+#endif
+}
+
+int PluginScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
+ int info_count = 0;
+#ifdef DEBUG_ENABLED
+ if (_desc.profiling_get_accumulated_data) {
+ godot_pluginscript_profiling_data *info = (godot_pluginscript_profiling_data *)memalloc(
+ sizeof(godot_pluginscript_profiling_data) * p_info_max);
+ info_count = _desc.profiling_get_accumulated_data(_data, info, p_info_max);
+ for (int i = 0; i < info_count; ++i) {
+ p_info_arr[i].signature = *(StringName *)&info[i].signature;
+ p_info_arr[i].call_count = info[i].call_count;
+ p_info_arr[i].total_time = info[i].total_time;
+ p_info_arr[i].self_time = info[i].self_time;
+ godot_string_name_destroy(&info[i].signature);
+ }
+ }
+#endif
+ return info_count;
+}
+
+int PluginScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
+ int info_count = 0;
+#ifdef DEBUG_ENABLED
+ if (_desc.profiling_get_frame_data) {
+ godot_pluginscript_profiling_data *info = (godot_pluginscript_profiling_data *)memalloc(
+ sizeof(godot_pluginscript_profiling_data) * p_info_max);
+ info_count = _desc.profiling_get_frame_data(_data, info, p_info_max);
+ for (int i = 0; i < info_count; ++i) {
+ p_info_arr[i].signature = *(StringName *)&info[i].signature;
+ p_info_arr[i].call_count = info[i].call_count;
+ p_info_arr[i].total_time = info[i].total_time;
+ p_info_arr[i].self_time = info[i].self_time;
+ godot_string_name_destroy(&info[i].signature);
+ }
+ }
+#endif
+ return info_count;
+}
+
+void PluginScriptLanguage::frame() {
+#ifdef DEBUG_ENABLED
+ if (_desc.profiling_frame) {
+ _desc.profiling_frame(_data);
+ }
+#endif
+}
+
+/* DEBUGGER FUNCTIONS */
+
+String PluginScriptLanguage::debug_get_error() const {
+ if (_desc.debug_get_error) {
+ godot_string tmp = _desc.debug_get_error(_data);
+ String ret = *(String *)&tmp;
+ godot_string_destroy(&tmp);
+ return ret;
+ }
+ return String("Nothing");
+}
+
+int PluginScriptLanguage::debug_get_stack_level_count() const {
+ if (_desc.debug_get_stack_level_count) {
+ return _desc.debug_get_stack_level_count(_data);
+ }
+ return 1;
+}
+
+int PluginScriptLanguage::debug_get_stack_level_line(int p_level) const {
+ if (_desc.debug_get_stack_level_line) {
+ return _desc.debug_get_stack_level_line(_data, p_level);
+ }
+ return 1;
+}
+
+String PluginScriptLanguage::debug_get_stack_level_function(int p_level) const {
+ if (_desc.debug_get_stack_level_function) {
+ godot_string tmp = _desc.debug_get_stack_level_function(_data, p_level);
+ String ret = *(String *)&tmp;
+ godot_string_destroy(&tmp);
+ return ret;
+ }
+ return String("Nothing");
+}
+
+String PluginScriptLanguage::debug_get_stack_level_source(int p_level) const {
+ if (_desc.debug_get_stack_level_source) {
+ godot_string tmp = _desc.debug_get_stack_level_source(_data, p_level);
+ String ret = *(String *)&tmp;
+ godot_string_destroy(&tmp);
+ return ret;
+ }
+ return String("Nothing");
+}
+
+void PluginScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
+ if (_desc.debug_get_stack_level_locals) {
+ PoolStringArray locals;
+ Array values;
+ _desc.debug_get_stack_level_locals(_data, p_level, (godot_pool_string_array *)&locals, (godot_array *)&values, p_max_subitems, p_max_depth);
+ for (int i = 0; i < locals.size(); i++) {
+ p_locals->push_back(locals[i]);
+ }
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+}
+
+void PluginScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
+ if (_desc.debug_get_stack_level_members) {
+ PoolStringArray members;
+ Array values;
+ _desc.debug_get_stack_level_members(_data, p_level, (godot_pool_string_array *)&members, (godot_array *)&values, p_max_subitems, p_max_depth);
+ for (int i = 0; i < members.size(); i++) {
+ p_members->push_back(members[i]);
+ }
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+}
+
+void PluginScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
+ if (_desc.debug_get_globals) {
+ PoolStringArray locals;
+ Array values;
+ _desc.debug_get_globals(_data, (godot_pool_string_array *)&locals, (godot_array *)&values, p_max_subitems, p_max_depth);
+ for (int i = 0; i < locals.size(); i++) {
+ p_locals->push_back(locals[i]);
+ }
+ for (int i = 0; i < values.size(); i++) {
+ p_values->push_back(values[i]);
+ }
+ }
+}
+
+String PluginScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
+ if (_desc.debug_parse_stack_level_expression) {
+ godot_string tmp = _desc.debug_parse_stack_level_expression(_data, p_level, (godot_string *)&p_expression, p_max_subitems, p_max_depth);
+ String ret = *(String *)&tmp;
+ godot_string_destroy(&tmp);
+ return ret;
+ }
+ return String("Nothing");
+}
+
+void PluginScriptLanguage::reload_all_scripts() {
+ // TODO
+}
+
+void PluginScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
+#ifdef DEBUG_ENABLED
+ lock();
+ // TODO
+ unlock();
+#endif
+}
+
+void PluginScriptLanguage::lock() {
+#ifndef NO_THREADS
+ if (_lock) {
+ _lock->lock();
+ }
+#endif
+}
+
+void PluginScriptLanguage::unlock() {
+#ifndef NO_THREADS
+ if (_lock) {
+ _lock->unlock();
+ }
+#endif
+}
+
+PluginScriptLanguage::PluginScriptLanguage(const godot_pluginscript_language_desc *desc)
+ : _desc(*desc) {
+ _resource_loader = memnew(ResourceFormatLoaderPluginScript(this));
+ _resource_saver = memnew(ResourceFormatSaverPluginScript(this));
+
+// TODO: totally remove _lock attribute if NO_THREADS is set
+#ifdef NO_THREADS
+ _lock = NULL;
+#else
+ _lock = Mutex::create();
+#endif
+}
+
+PluginScriptLanguage::~PluginScriptLanguage() {
+ memdelete(_resource_loader);
+ memdelete(_resource_saver);
+#ifndef NO_THREADS
+ if (_lock) {
+ memdelete(_lock);
+ _lock = NULL;
+ }
+#endif
+}
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
new file mode 100644
index 0000000000..79b95ff4e6
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -0,0 +1,132 @@
+/*************************************************************************/
+/* pluginscript_language.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PLUGINSCRIPT_LANGUAGE_H
+#define PLUGINSCRIPT_LANGUAGE_H
+
+// 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"
+// PluginScript imports
+#include "pluginscript_loader.h"
+#include <pluginscript/godot_pluginscript.h>
+
+class PluginScript;
+class PluginScriptInstance;
+
+class PluginScriptLanguage : public ScriptLanguage {
+ friend class PluginScript;
+ friend class PluginScriptInstance;
+
+ ResourceFormatLoaderPluginScript *_resource_loader;
+ ResourceFormatSaverPluginScript *_resource_saver;
+ const godot_pluginscript_language_desc _desc;
+ godot_pluginscript_language_data *_data;
+
+ Mutex *_lock;
+ SelfList<PluginScript>::List _script_list;
+
+public:
+ virtual String get_name() const;
+
+ _FORCE_INLINE_ ResourceFormatLoaderPluginScript *get_resource_loader() { return _resource_loader; };
+ _FORCE_INLINE_ ResourceFormatSaverPluginScript *get_resource_saver() { return _resource_saver; };
+
+ /* LANGUAGE FUNCTIONS */
+ virtual void init();
+ virtual String get_type() const;
+ virtual String get_extension() const;
+ virtual Error execute_file(const String &p_path);
+ virtual void finish();
+
+ /* EDITOR FUNCTIONS */
+ virtual void get_reserved_words(List<String> *p_words) const;
+ virtual void get_comment_delimiters(List<String> *p_delimiters) const;
+ virtual void get_string_delimiters(List<String> *p_delimiters) const;
+ virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
+ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const;
+ 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 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 PoolStringArray &p_args) const;
+ virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint);
+ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
+ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value);
+
+ /* MULTITHREAD FUNCTIONS */
+
+ //some VMs need to be notified of thread creation/exiting to allocate a stack
+ // void thread_enter() {}
+ // void thread_exit() {}
+
+ /* DEBUGGER FUNCTIONS */
+
+ virtual String debug_get_error() const;
+ virtual int debug_get_stack_level_count() const;
+ virtual int debug_get_stack_level_line(int p_level) const;
+ virtual String debug_get_stack_level_function(int p_level) const;
+ virtual String debug_get_stack_level_source(int p_level) const;
+ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
+ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
+ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
+ virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1);
+
+ // virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); }
+
+ virtual void reload_all_scripts();
+ virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload);
+
+ /* LOADER FUNCTIONS */
+
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual void get_public_functions(List<MethodInfo> *p_functions) const;
+ virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const;
+
+ virtual void profiling_start();
+ virtual void profiling_stop();
+
+ virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max);
+ virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max);
+
+ virtual void frame();
+
+ void lock();
+ void unlock();
+
+ PluginScriptLanguage(const godot_pluginscript_language_desc *desc);
+ virtual ~PluginScriptLanguage();
+};
+
+#endif // PLUGINSCRIPT_LANGUAGE_H
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp
new file mode 100644
index 0000000000..3648e1a5b4
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp
@@ -0,0 +1,113 @@
+/*************************************************************************/
+/* pluginscript_loader.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+// Godot imports
+#include "os/file_access.h"
+// Pythonscript imports
+#include "pluginscript_language.h"
+#include "pluginscript_loader.h"
+#include "pluginscript_script.h"
+
+ResourceFormatLoaderPluginScript::ResourceFormatLoaderPluginScript(PluginScriptLanguage *language) {
+ _language = language;
+}
+
+RES ResourceFormatLoaderPluginScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error = ERR_FILE_CANT_OPEN;
+
+ PluginScript *script = memnew(PluginScript);
+ script->init(_language);
+
+ Ref<PluginScript> scriptres(script);
+
+ Error err = script->load_source_code(p_path);
+ ERR_FAIL_COND_V(err != OK, RES());
+
+ script->set_path(p_original_path);
+
+ script->reload();
+
+ if (r_error)
+ *r_error = OK;
+
+ return scriptres;
+}
+
+void ResourceFormatLoaderPluginScript::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back(_language->get_extension());
+}
+
+bool ResourceFormatLoaderPluginScript::handles_type(const String &p_type) const {
+ return p_type == "Script" || p_type == _language->get_type();
+}
+
+String ResourceFormatLoaderPluginScript::get_resource_type(const String &p_path) const {
+ String el = p_path.get_extension().to_lower();
+ if (el == _language->get_extension())
+ return _language->get_type();
+ return "";
+}
+
+ResourceFormatSaverPluginScript::ResourceFormatSaverPluginScript(PluginScriptLanguage *language) {
+ _language = language;
+}
+
+Error ResourceFormatSaverPluginScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+ Ref<PluginScript> sqscr = p_resource;
+ ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
+
+ String source = sqscr->get_source_code();
+
+ Error err;
+ FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(err, err);
+
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ memdelete(file);
+ return ERR_CANT_CREATE;
+ }
+ file->close();
+ memdelete(file);
+ return OK;
+}
+
+void ResourceFormatSaverPluginScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+
+ if (Object::cast_to<PluginScript>(*p_resource)) {
+ p_extensions->push_back(_language->get_extension());
+ }
+}
+
+bool ResourceFormatSaverPluginScript::recognize(const RES &p_resource) const {
+
+ return Object::cast_to<PluginScript>(*p_resource) != NULL;
+}
diff --git a/modules/gdnative/pluginscript/pluginscript_loader.h b/modules/gdnative/pluginscript/pluginscript_loader.h
new file mode 100644
index 0000000000..b85e7725a1
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_loader.h
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* pluginscript_loader.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PYTHONSCRIPT_PY_LOADER_H
+#define PYTHONSCRIPT_PY_LOADER_H
+
+// Godot imports
+#include "core/script_language.h"
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+
+class PluginScriptLanguage;
+
+class ResourceFormatLoaderPluginScript : public ResourceFormatLoader {
+ PluginScriptLanguage *_language;
+
+public:
+ ResourceFormatLoaderPluginScript(PluginScriptLanguage *language);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class ResourceFormatSaverPluginScript : public ResourceFormatSaver {
+ PluginScriptLanguage *_language;
+
+public:
+ ResourceFormatSaverPluginScript(PluginScriptLanguage *language);
+ virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const RES &p_resource) const;
+};
+
+#endif // PYTHONSCRIPT_PY_LOADER_H
diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp
new file mode 100644
index 0000000000..4169b07f63
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_script.cpp
@@ -0,0 +1,449 @@
+/*************************************************************************/
+/* pluginscript_script.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+// Godot imports
+#include "core/os/file_access.h"
+// PluginScript imports
+#include "pluginscript_instance.h"
+#include "pluginscript_script.h"
+
+#if DEBUG_ENABLED
+#define __ASSERT_SCRIPT_REASON "Cannot retrieve pluginscript class for this script, is you code correct ?"
+#define ASSERT_SCRIPT_VALID() \
+ { \
+ ERR_EXPLAIN(__ASSERT_SCRIPT_REASON); \
+ ERR_FAIL_COND(!can_instance()) \
+ }
+#define ASSERT_SCRIPT_VALID_V(ret) \
+ { \
+ ERR_EXPLAIN(__ASSERT_SCRIPT_REASON); \
+ ERR_FAIL_COND_V(!can_instance(), ret) \
+ }
+#else
+#define ASSERT_SCRIPT_VALID()
+#define ASSERT_SCRIPT_VALID_V(ret)
+#endif
+
+void PluginScript::_bind_methods() {
+}
+
+#ifdef TOOLS_ENABLED
+
+void PluginScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
+ placeholders.erase(p_placeholder);
+}
+
+#endif
+
+bool PluginScript::can_instance() const {
+ bool can = _valid || (!_tool && !ScriptServer::is_scripting_enabled());
+ return can;
+}
+
+Ref<Script> PluginScript::get_base_script() const {
+ if (_ref_base_parent.is_valid()) {
+ return Ref<PluginScript>(_ref_base_parent);
+ } else {
+ return Ref<Script>();
+ }
+}
+
+StringName PluginScript::get_instance_base_type() const {
+ if (_native_parent)
+ return _native_parent;
+ if (_ref_base_parent.is_valid())
+ return _ref_base_parent->get_instance_base_type();
+ return StringName();
+}
+
+void PluginScript::update_exports() {
+// TODO
+#ifdef TOOLS_ENABLED
+#if 0
+ ASSERT_SCRIPT_VALID();
+ if (/*changed &&*/ placeholders.size()) { //hm :(
+
+ //update placeholders if any
+ Map<StringName, Variant> propdefvalues;
+ List<PropertyInfo> propinfos;
+ const String *props = (const String *)pybind_get_prop_list(_py_exposed_class);
+ for (int i = 0; props[i] != ""; ++i) {
+ const String propname = props[i];
+ pybind_get_prop_default_value(_py_exposed_class, propname.c_str(), (godot_variant *)&propdefvalues[propname]);
+ pybind_prop_info raw_info;
+ pybind_get_prop_info(_py_exposed_class, propname.c_str(), &raw_info);
+ PropertyInfo info;
+ info.type = (Variant::Type)raw_info.type;
+ info.name = propname;
+ info.hint = (PropertyHint)raw_info.hint;
+ info.hint_string = *(String *)&raw_info.hint_string;
+ info.usage = raw_info.usage;
+ propinfos.push_back(info);
+ }
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->update(propinfos, propdefvalues);
+ }
+ }
+#endif
+#endif
+}
+
+// TODO: rename p_this "p_owner" ?
+ScriptInstance *PluginScript::instance_create(Object *p_this) {
+ ASSERT_SCRIPT_VALID_V(NULL);
+ // TODO check script validity ?
+ if (!_tool && !ScriptServer::is_scripting_enabled()) {
+#ifdef TOOLS_ENABLED
+ // Instance a fake script for editing the values
+ PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(get_language(), Ref<Script>(this), p_this));
+ placeholders.insert(si);
+ update_exports();
+ return si;
+#else
+ return NULL;
+#endif
+ }
+
+ PluginScript *top = this;
+ // TODO: can be optimized by storing a PluginScript::_base_parent direct pointer
+ while (top->_ref_base_parent.is_valid())
+ top = top->_ref_base_parent.ptr();
+ if (top->_native_parent) {
+ if (!ClassDB::is_parent_class(p_this->get_class_name(), top->_native_parent)) {
+ String msg = "Script inherits from native type '" + String(top->_native_parent) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'";
+ // TODO: implement PluginscriptLanguage::debug_break_parse
+ // if (ScriptDebugger::get_singleton()) {
+ // _language->debug_break_parse(get_path(), 0, msg);
+ // }
+ ERR_EXPLAIN(msg);
+ ERR_FAIL_V(NULL);
+ }
+ }
+
+ PluginScriptInstance *instance = memnew(PluginScriptInstance());
+ const bool success = instance->init(this, p_this);
+ if (success) {
+ _language->lock();
+ _instances.insert(instance->get_owner());
+ _language->unlock();
+ return instance;
+ } else {
+ memdelete(instance);
+ ERR_FAIL_V(NULL);
+ }
+}
+
+bool PluginScript::instance_has(const Object *p_this) const {
+ _language->lock();
+ bool hasit = _instances.has((Object *)p_this);
+ _language->unlock();
+ return hasit;
+}
+
+bool PluginScript::has_source_code() const {
+ bool has = _source != "";
+ return has;
+}
+
+String PluginScript::get_source_code() const {
+ return _source;
+}
+
+void PluginScript::set_source_code(const String &p_code) {
+ if (_source == p_code)
+ return;
+ _source = p_code;
+}
+
+Error PluginScript::reload(bool p_keep_state) {
+ _language->lock();
+ ERR_FAIL_COND_V(!p_keep_state && _instances.size(), ERR_ALREADY_IN_USE);
+ _language->unlock();
+
+ _valid = false;
+ String basedir = _path;
+
+ if (basedir == "")
+ basedir = get_path();
+
+ if (basedir != "")
+ basedir = basedir.get_base_dir();
+
+ if (_data) {
+ _desc->finish(_data);
+ }
+
+ Error err;
+ godot_pluginscript_script_manifest manifest = _desc->init(
+ _language->_data,
+ (godot_string *)&_path,
+ (godot_string *)&_source,
+ (godot_error *)&err);
+ if (err) {
+ // TODO: GDscript uses `ScriptDebugger` here to jump into the parsing error
+ return err;
+ }
+ _valid = true;
+ // Use the manifest to configure this script object
+ _data = manifest.data;
+ _name = *(StringName *)&manifest.name;
+ _tool = manifest.is_tool;
+ // Base name is either another PluginScript or a regular class accessible
+ // through ClassDB
+ StringName *base_name = (StringName *)&manifest.base;
+ for (SelfList<PluginScript> *e = _language->_script_list.first(); e != NULL; e = e->next()) {
+ if (e->self()->_name == *base_name) {
+ // Found you, base is a PluginScript !
+ _ref_base_parent = Ref<PluginScript>(e->self());
+ break;
+ }
+ }
+ if (!_ref_base_parent.is_valid()) {
+ // Base is a native ClassDB
+ if (!ClassDB::class_exists(*base_name)) {
+ ERR_EXPLAIN("Unknown script '" + String(_name) + "' parent '" + String(*base_name) + "'.");
+ ERR_FAIL_V(ERR_PARSE_ERROR);
+ }
+ _native_parent = *base_name;
+ }
+
+ Dictionary *members = (Dictionary *)&manifest.member_lines;
+ for (const Variant *key = members->next(); key != NULL; key = members->next(key)) {
+ _member_lines[*key] = (*members)[key];
+ }
+ Array *methods = (Array *)&manifest.methods;
+ for (int i = 0; i < methods->size(); ++i) {
+ Dictionary v = (*methods)[i];
+ MethodInfo mi = MethodInfo::from_dict(v);
+ _methods_info[mi.name] = mi;
+ // rpc_mode is passed as an optional field and is not part of MethodInfo
+ Variant var = v["rpc_mode"];
+ if (var == Variant()) {
+ _methods_rpc_mode[mi.name] = ScriptInstance::RPC_MODE_DISABLED;
+ } else {
+ _methods_rpc_mode[mi.name] = ScriptInstance::RPCMode(int(var));
+ }
+ }
+ Array *signals = (Array *)&manifest.signals;
+ for (int i = 0; i < signals->size(); ++i) {
+ Variant v = (*signals)[i];
+ MethodInfo mi = MethodInfo::from_dict(v);
+ _signals_info[mi.name] = mi;
+ }
+ Array *properties = (Array *)&manifest.properties;
+ for (int i = 0; i < properties->size(); ++i) {
+ Dictionary v = (*properties)[i];
+ PropertyInfo pi = PropertyInfo::from_dict(v);
+ _properties_info[pi.name] = pi;
+ _properties_default_values[pi.name] = v["default_value"];
+ // rset_mode is passed as an optional field and is not part of PropertyInfo
+ Variant var = v["rset_mode"];
+ if (var == Variant()) {
+ _methods_rpc_mode[pi.name] = ScriptInstance::RPC_MODE_DISABLED;
+ } else {
+ _methods_rpc_mode[pi.name] = ScriptInstance::RPCMode(int(var));
+ }
+ }
+ // Manifest's attributes must be explicitly freed
+ godot_string_name_destroy(&manifest.name);
+ godot_string_name_destroy(&manifest.base);
+ godot_dictionary_destroy(&manifest.member_lines);
+ godot_array_destroy(&manifest.methods);
+ godot_array_destroy(&manifest.signals);
+ godot_array_destroy(&manifest.properties);
+
+#ifdef TOOLS_ENABLED
+/*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) {
+
+ _update_placeholder(E->get());
+ }*/
+#endif
+ return OK;
+}
+
+void PluginScript::get_script_method_list(List<MethodInfo> *r_methods) const {
+ ASSERT_SCRIPT_VALID();
+ for (Map<StringName, MethodInfo>::Element *e = _methods_info.front(); e != NULL; e = e->next()) {
+ r_methods->push_back(e->get());
+ }
+}
+
+void PluginScript::get_script_property_list(List<PropertyInfo> *r_properties) const {
+ ASSERT_SCRIPT_VALID();
+ for (Map<StringName, PropertyInfo>::Element *e = _properties_info.front(); e != NULL; e = e->next()) {
+ r_properties->push_back(e->get());
+ }
+}
+
+bool PluginScript::has_method(const StringName &p_method) const {
+ ASSERT_SCRIPT_VALID_V(false);
+ return _methods_info.has(p_method);
+}
+
+MethodInfo PluginScript::get_method_info(const StringName &p_method) const {
+ ASSERT_SCRIPT_VALID_V(MethodInfo());
+ const Map<StringName, MethodInfo>::Element *e = _methods_info.find(p_method);
+ if (e != NULL) {
+ return e->get();
+ } else {
+ return MethodInfo();
+ }
+}
+
+bool PluginScript::has_property(const StringName &p_method) const {
+ ASSERT_SCRIPT_VALID_V(false);
+ return _properties_info.has(p_method);
+}
+
+PropertyInfo PluginScript::get_property_info(const StringName &p_property) const {
+ ASSERT_SCRIPT_VALID_V(PropertyInfo());
+ const Map<StringName, PropertyInfo>::Element *e = _properties_info.find(p_property);
+ if (e != NULL) {
+ return e->get();
+ } else {
+ return PropertyInfo();
+ }
+}
+
+bool PluginScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
+ ASSERT_SCRIPT_VALID_V(false);
+#ifdef TOOLS_ENABLED
+ const Map<StringName, Variant>::Element *e = _properties_default_values.find(p_property);
+ if (e != NULL) {
+ r_value = e->get();
+ return true;
+ } else {
+ return false;
+ }
+#endif
+ return false;
+}
+
+ScriptLanguage *PluginScript::get_language() const {
+ return _language;
+}
+
+Error PluginScript::load_source_code(const String &p_path) {
+
+ PoolVector<uint8_t> sourcef;
+ Error err;
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (err) {
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ int len = f->get_len();
+ sourcef.resize(len + 1);
+ PoolVector<uint8_t>::Write w = sourcef.write();
+ int r = f->get_buffer(w.ptr(), len);
+ f->close();
+ memdelete(f);
+ ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
+ w[len] = 0;
+
+ String s;
+ if (s.parse_utf8((const char *)w.ptr())) {
+ ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
+ ERR_FAIL_V(ERR_INVALID_DATA);
+ }
+
+ _source = s;
+#ifdef TOOLS_ENABLED
+// source_changed_cache=true;
+#endif
+ _path = p_path;
+ return OK;
+}
+
+bool PluginScript::has_script_signal(const StringName &p_signal) const {
+ ASSERT_SCRIPT_VALID_V(false);
+ return _signals_info.has(p_signal);
+}
+
+void PluginScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+ ASSERT_SCRIPT_VALID();
+ for (Map<StringName, MethodInfo>::Element *e = _signals_info.front(); e != NULL; e = e->next()) {
+ r_signals->push_back(e->get());
+ }
+}
+
+int PluginScript::get_member_line(const StringName &p_member) const {
+#ifdef TOOLS_ENABLED
+ if (_member_lines.has(p_member))
+ return _member_lines[p_member];
+ else
+#endif
+ return -1;
+}
+
+ScriptInstance::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const {
+ ASSERT_SCRIPT_VALID_V(ScriptInstance::RPC_MODE_DISABLED);
+ const Map<StringName, ScriptInstance::RPCMode>::Element *e = _methods_rpc_mode.find(p_method);
+ if (e != NULL) {
+ return e->get();
+ } else {
+ return ScriptInstance::RPC_MODE_DISABLED;
+ }
+}
+
+ScriptInstance::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const {
+ ASSERT_SCRIPT_VALID_V(ScriptInstance::RPC_MODE_DISABLED);
+ const Map<StringName, ScriptInstance::RPCMode>::Element *e = _variables_rset_mode.find(p_variable);
+ if (e != NULL) {
+ return e->get();
+ } else {
+ return ScriptInstance::RPC_MODE_DISABLED;
+ }
+}
+
+PluginScript::PluginScript()
+ : _data(NULL), _tool(false), _valid(false), _script_list(this) {
+}
+
+void PluginScript::init(PluginScriptLanguage *language) {
+ _desc = &language->_desc.script_desc;
+ _language = language;
+
+#ifdef DEBUG_ENABLED
+ _language->lock();
+ _language->_script_list.add(&_script_list);
+ _language->unlock();
+#endif
+}
+
+PluginScript::~PluginScript() {
+ _desc->finish(_data);
+
+#ifdef DEBUG_ENABLED
+ _language->lock();
+ _language->_script_list.remove(&_script_list);
+ _language->unlock();
+#endif
+}
diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h
new file mode 100644
index 0000000000..5600bca5ef
--- /dev/null
+++ b/modules/gdnative/pluginscript/pluginscript_script.h
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/* pluginscript_script.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef PLUGINSCRIPT_SCRIPT_H
+#define PLUGINSCRIPT_SCRIPT_H
+
+// Godot imports
+#include "core/script_language.h"
+// PluginScript imports
+#include "pluginscript_language.h"
+#include <pluginscript/godot_pluginscript.h>
+
+class PyInstance;
+
+class PluginScript : public Script {
+
+ GDCLASS(PluginScript, Script);
+
+ friend class PluginScriptInstance;
+ friend class PluginScriptLanguage;
+
+private:
+ godot_pluginscript_script_data *_data;
+ const godot_pluginscript_script_desc *_desc;
+ PluginScriptLanguage *_language;
+ bool _tool;
+ bool _valid;
+
+ Ref<PluginScript> _ref_base_parent;
+ StringName _native_parent;
+ SelfList<PluginScript> _script_list;
+
+ Map<StringName, int> _member_lines;
+ Map<StringName, Variant> _properties_default_values;
+ Map<StringName, PropertyInfo> _properties_info;
+ Map<StringName, MethodInfo> _signals_info;
+ Map<StringName, MethodInfo> _methods_info;
+ Map<StringName, ScriptInstance::RPCMode> _variables_rset_mode;
+ Map<StringName, ScriptInstance::RPCMode> _methods_rpc_mode;
+
+ Set<Object *> _instances;
+ //exported members
+ String _source;
+ String _path;
+ StringName _name;
+
+protected:
+ static void _bind_methods();
+
+#ifdef TOOLS_ENABLED
+ Set<PlaceHolderScriptInstance *> placeholders;
+ //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
+ virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
+#endif
+public:
+ virtual bool can_instance() const;
+
+ virtual Ref<Script> get_base_script() const; //for script inheritance
+
+ virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so
+ virtual ScriptInstance *instance_create(Object *p_this);
+ virtual bool instance_has(const Object *p_this) const;
+
+ virtual bool has_source_code() const;
+ virtual String get_source_code() const;
+ virtual void set_source_code(const String &p_code);
+ virtual Error reload(bool p_keep_state = false);
+ // TODO: load_source_code only allow utf-8 file, should handle bytecode as well ?
+ virtual Error load_source_code(const String &p_path);
+
+ virtual bool has_method(const StringName &p_method) const;
+ virtual MethodInfo get_method_info(const StringName &p_method) const;
+
+ bool has_property(const StringName &p_method) const;
+ PropertyInfo get_property_info(const StringName &p_property) const;
+
+ bool is_tool() const { return _tool; }
+
+ virtual ScriptLanguage *get_language() const;
+
+ virtual bool has_script_signal(const StringName &p_signal) const;
+ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
+
+ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const;
+
+ virtual void update_exports();
+ virtual void get_script_method_list(List<MethodInfo> *r_methods) const;
+ virtual void get_script_property_list(List<PropertyInfo> *r_propertieslist) const;
+
+ virtual int get_member_line(const StringName &p_member) const;
+
+ ScriptInstance::RPCMode get_rpc_mode(const StringName &p_method) const;
+ ScriptInstance::RPCMode get_rset_mode(const StringName &p_variable) const;
+
+ PluginScript();
+ void init(PluginScriptLanguage *language);
+ virtual ~PluginScript();
+};
+
+#endif // PLUGINSCRIPT_SCRIPT_H
diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp
new file mode 100644
index 0000000000..5829d08dff
--- /dev/null
+++ b/modules/gdnative/pluginscript/register_types.cpp
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "core/project_settings.h"
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "os/dir_access.h"
+#include "os/os.h"
+#include "scene/main/scene_tree.h"
+
+#include "pluginscript_language.h"
+#include "pluginscript_script.h"
+#include <pluginscript/godot_pluginscript.h>
+
+static List<PluginScriptLanguage *> pluginscript_languages;
+
+static Error _check_language_desc(const godot_pluginscript_language_desc *desc) {
+ ERR_FAIL_COND_V(!desc->name || desc->name == String(), ERR_BUG);
+ ERR_FAIL_COND_V(!desc->type || desc->type == String(), ERR_BUG);
+ ERR_FAIL_COND_V(!desc->extension || desc->extension == String(), ERR_BUG);
+ ERR_FAIL_COND_V(!desc->recognized_extensions || !desc->recognized_extensions[0], ERR_BUG);
+ ERR_FAIL_COND_V(!desc->init, ERR_BUG);
+ ERR_FAIL_COND_V(!desc->finish, ERR_BUG);
+
+ // desc->reserved_words is not mandatory
+ // desc->comment_delimiters is not mandatory
+ // desc->string_delimiters is not mandatory
+
+ // desc->get_template_source_code is not mandatory
+ // desc->validate is not mandatory
+
+ // desc->get_template_source_code is not mandatory
+ // desc->validate is not mandatory
+ // desc->find_function is not mandatory
+ // desc->make_function is not mandatory
+ // desc->complete_code is not mandatory
+ // desc->auto_indent_code is not mandatory
+ // desc->add_global_constant is not mandatory
+ // desc->debug_get_error is not mandatory
+ // desc->debug_get_stack_level_count is not mandatory
+ // desc->debug_get_stack_level_line is not mandatory
+ // desc->debug_get_stack_level_function is not mandatory
+ // desc->debug_get_stack_level_source is not mandatory
+ // desc->debug_get_stack_level_locals is not mandatory
+ // desc->debug_get_stack_level_members is not mandatory
+ // desc->debug_get_globals is not mandatory
+ // desc->debug_parse_stack_level_expression is not mandatory
+ // desc->profiling_start is not mandatory
+ // desc->profiling_stop is not mandatory
+ // desc->profiling_get_accumulated_data is not mandatory
+ // desc->profiling_get_frame_data is not mandatory
+ // desc->frame is not mandatory
+
+ ERR_FAIL_COND_V(!desc->script_desc.init, ERR_BUG);
+ ERR_FAIL_COND_V(!desc->script_desc.finish, ERR_BUG);
+
+ ERR_FAIL_COND_V(!desc->script_desc.instance_desc.init, ERR_BUG);
+ ERR_FAIL_COND_V(!desc->script_desc.instance_desc.finish, ERR_BUG);
+ ERR_FAIL_COND_V(!desc->script_desc.instance_desc.set_prop, ERR_BUG);
+ ERR_FAIL_COND_V(!desc->script_desc.instance_desc.get_prop, ERR_BUG);
+ ERR_FAIL_COND_V(!desc->script_desc.instance_desc.call_method, ERR_BUG);
+ ERR_FAIL_COND_V(!desc->script_desc.instance_desc.notification, ERR_BUG);
+ // desc->script_desc.instance_desc.refcount_incremented is not mandatory
+ // desc->script_desc.instance_desc.refcount_decremented is not mandatory
+ return OK;
+}
+
+void GDAPI godot_pluginscript_register_language(const godot_pluginscript_language_desc *language_desc) {
+ Error ret = _check_language_desc(language_desc);
+ if (ret) {
+ ERR_FAIL();
+ }
+ PluginScriptLanguage *language = memnew(PluginScriptLanguage(language_desc));
+ ScriptServer::register_language(language);
+ ResourceLoader::add_resource_format_loader(language->get_resource_loader());
+ ResourceSaver::add_resource_format_saver(language->get_resource_saver());
+ pluginscript_languages.push_back(language);
+}
+
+void register_pluginscript_types() {
+ ClassDB::register_class<PluginScript>();
+}
+
+void unregister_pluginscript_types() {
+ for (List<PluginScriptLanguage *>::Element *e = pluginscript_languages.front(); e; e = e->next()) {
+ PluginScriptLanguage *language = e->get();
+ ScriptServer::unregister_language(language);
+ memdelete(language);
+ }
+}
diff --git a/modules/gdnative/pluginscript/register_types.h b/modules/gdnative/pluginscript/register_types.h
new file mode 100644
index 0000000000..70bbb16c62
--- /dev/null
+++ b/modules/gdnative/pluginscript/register_types.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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_pluginscript_types();
+void unregister_pluginscript_types();
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 997c342045..87f9cddaa2 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -35,7 +35,9 @@
#include "io/resource_loader.h"
#include "io/resource_saver.h"
+#include "nativearvr/register_types.h"
#include "nativescript/register_types.h"
+#include "pluginscript/register_types.h"
#include "core/engine.h"
#include "core/os/os.h"
@@ -127,57 +129,12 @@ static void editor_init_callback() {
#endif
-godot_variant cb_standard_varcall(void *handle, godot_string *p_procedure, godot_array *p_args) {
- if (handle == NULL) {
- ERR_PRINT("No valid library handle, can't call standard varcall procedure");
- godot_variant ret;
- godot_variant_new_nil(&ret);
- return ret;
- }
-
- void *library_proc;
- Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
- handle,
- *(String *)p_procedure,
- library_proc,
- true); // we roll our own message
- if (err != OK) {
- ERR_PRINT((String("GDNative procedure \"" + *(String *)p_procedure) + "\" does not exists and can't be called").utf8().get_data());
- godot_variant ret;
- godot_variant_new_nil(&ret);
- return ret;
- }
+godot_variant cb_standard_varcall(void *p_procedure_handle, godot_array *p_args) {
godot_gdnative_procedure_fn proc;
- proc = (godot_gdnative_procedure_fn)library_proc;
-
- return proc(NULL, p_args);
-}
-
-void cb_singleton_call(
- void *p_handle,
- godot_string *p_proc_name,
- void *p_data,
- int p_num_args,
- void **p_args,
- void *r_return) {
- if (p_handle == NULL) {
- ERR_PRINT("No valid library handle, can't call singleton procedure");
- return;
- }
+ proc = (godot_gdnative_procedure_fn)p_procedure_handle;
- void *singleton_proc;
- Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
- p_handle,
- *(String *)p_proc_name,
- singleton_proc);
-
- if (err != OK) {
- return;
- }
-
- void (*singleton_procedure_ptr)() = (void (*)())singleton_proc;
- singleton_procedure_ptr();
+ return proc(p_args);
}
GDNativeCallRegistry *GDNativeCallRegistry::singleton;
@@ -200,13 +157,16 @@ void register_gdnative_types() {
GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall);
- GDNativeCallRegistry::singleton->register_native_raw_call_type("gdnative_singleton_call", cb_singleton_call);
-
+ register_nativearvr_types();
register_nativescript_types();
+ register_pluginscript_types();
// run singletons
- Array singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ Array singletons = Array();
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
+ singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ }
singleton_gdnatives.resize(singletons.size());
@@ -223,13 +183,16 @@ void register_gdnative_types() {
continue;
}
- singleton_gdnatives[i]->call_native_raw(
- "gdnative_singleton_call",
+ void *proc_ptr;
+ Error err = singleton_gdnatives[i]->get_symbol(
"godot_gdnative_singleton",
- NULL,
- 0,
- NULL,
- NULL);
+ proc_ptr);
+
+ if (err != OK) {
+ ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton_gdnatives[i]->get_library()->get_active_library_path()) + "\" found").utf8().get_data());
+ } else {
+ ((void (*)())proc_ptr)();
+ }
}
}
@@ -247,8 +210,11 @@ void unregister_gdnative_types() {
singleton_gdnatives[i]->terminate();
}
+ singleton_gdnatives.clear();
+ unregister_pluginscript_types();
unregister_nativescript_types();
+ unregister_nativearvr_types();
memdelete(GDNativeCallRegistry::singleton);
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp
index 4803781c67..7036a708e5 100644
--- a/modules/gdscript/gd_compiler.cpp
+++ b/modules/gdscript/gd_compiler.cpp
@@ -131,7 +131,7 @@ int GDCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDParser:
switch (p_expression->op) {
case GDParser::OperatorNode::OP_ASSIGN_ADD: var_op = Variant::OP_ADD; break;
- case GDParser::OperatorNode::OP_ASSIGN_SUB: var_op = Variant::OP_SUBSTRACT; break;
+ case GDParser::OperatorNode::OP_ASSIGN_SUB: var_op = Variant::OP_SUBTRACT; break;
case GDParser::OperatorNode::OP_ASSIGN_MUL: var_op = Variant::OP_MULTIPLY; break;
case GDParser::OperatorNode::OP_ASSIGN_DIV: var_op = Variant::OP_DIVIDE; break;
case GDParser::OperatorNode::OP_ASSIGN_MOD: var_op = Variant::OP_MODULE; break;
@@ -759,7 +759,7 @@ int GDCompiler::_parse_expression(CodeGen &codegen, const GDParser::Node *p_expr
if (!_create_binary_operator(codegen, on, Variant::OP_ADD, p_stack_level)) return -1;
} break;
case GDParser::OperatorNode::OP_SUB: {
- if (!_create_binary_operator(codegen, on, Variant::OP_SUBSTRACT, p_stack_level)) return -1;
+ if (!_create_binary_operator(codegen, on, Variant::OP_SUBTRACT, p_stack_level)) return -1;
} break;
case GDParser::OperatorNode::OP_MUL: {
if (!_create_binary_operator(codegen, on, Variant::OP_MULTIPLY, p_stack_level)) return -1;
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index bc51b84047..d9b10ff3fa 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -61,7 +61,11 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str
"func _ready():\n" +
"%TS%# Called every time the node is added to the scene.\n" +
"%TS%# Initialization here\n" +
- "%TS%pass\n";
+ "%TS%pass\n\n" +
+ "#func _process(delta):\n" +
+ "#%TS%# Called every frame. Delta is time since last frame.\n" +
+ "#%TS%# Update game logic here.\n" +
+ "#%TS%pass\n";
_template = _template.replace("%BASE%", p_base_class_name);
_template = _template.replace("%TS%", _get_indentation());
@@ -127,6 +131,11 @@ bool GDScriptLanguage::has_named_classes() const {
return false;
}
+bool GDScriptLanguage::supports_builtin_mode() const {
+
+ return true;
+}
+
int GDScriptLanguage::find_function(const String &p_function, const String &p_code) const {
GDTokenizerText tokenizer;
@@ -908,7 +917,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser:
Variant::Operator vop = Variant::OP_MAX;
switch (op->op) {
case GDParser::OperatorNode::OP_ADD: vop = Variant::OP_ADD; break;
- case GDParser::OperatorNode::OP_SUB: vop = Variant::OP_SUBSTRACT; break;
+ case GDParser::OperatorNode::OP_SUB: vop = Variant::OP_SUBTRACT; break;
case GDParser::OperatorNode::OP_MUL: vop = Variant::OP_MULTIPLY; break;
case GDParser::OperatorNode::OP_DIV: vop = Variant::OP_DIVIDE; break;
case GDParser::OperatorNode::OP_MOD: vop = Variant::OP_MODULE; break;
@@ -1952,7 +1961,6 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N
//make sure identifier exists...
const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[1]);
-
if (op->arguments[0]->type == GDParser::Node::TYPE_SELF) {
//self, look up
@@ -2021,7 +2029,7 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N
base = script->get_native();
} else if (nc.is_valid()) {
- if (context.function && !context.function->_static) {
+ if (!(context.function && context.function->_static)) {
GDCompletionIdentifier ci;
ci.type = Variant::OBJECT;
@@ -2103,9 +2111,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
for (List<String>::Element *E = opts.front(); E; E = E->next()) {
String opt = E->get().strip_edges();
- if (opt.begins_with("\"") && opt.ends_with("\"")) {
+ if (opt.is_quoted()) {
r_forced = true;
- String idopt = opt.substr(1, opt.length() - 2);
+ String idopt = opt.unquote();
if (idopt.replace("/", "_").is_valid_identifier()) {
options.insert(idopt);
} else {
diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp
index ddee7b2521..ce503b62f2 100644
--- a/modules/gdscript/gd_function.cpp
+++ b/modules/gdscript/gd_function.cpp
@@ -41,11 +41,12 @@ Variant *GDFunction::_get_variant(int p_address, GDInstance *p_instance, GDScrip
switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
case ADDR_TYPE_SELF: {
-
- if (!p_instance) {
+#ifdef DEBUG_ENABLED
+ if (unlikely(!p_instance)) {
r_error = "Cannot access self without instance.";
return NULL;
}
+#endif
return &self;
} break;
case ADDR_TYPE_CLASS: {
@@ -53,18 +54,22 @@ Variant *GDFunction::_get_variant(int p_address, GDInstance *p_instance, GDScrip
return &p_script->_static_ref;
} break;
case ADDR_TYPE_MEMBER: {
- //member indexing is O(1)
- if (!p_instance) {
+#ifdef DEBUG_ENABLED
+ if (unlikely(!p_instance)) {
r_error = "Cannot access member without instance.";
return NULL;
}
+#endif
+ //member indexing is O(1)
return &p_instance->members[address];
} break;
case ADDR_TYPE_CLASS_CONSTANT: {
//todo change to index!
GDScript *o = p_script;
+#ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(address, _global_names_count, NULL);
+#endif
const StringName *sn = &_global_names_ptr[address];
while (o) {
@@ -84,18 +89,22 @@ Variant *GDFunction::_get_variant(int p_address, GDInstance *p_instance, GDScrip
ERR_FAIL_V(NULL);
} break;
case ADDR_TYPE_LOCAL_CONSTANT: {
+#ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(address, _constant_count, NULL);
+#endif
return &_constants_ptr[address];
} break;
case ADDR_TYPE_STACK:
case ADDR_TYPE_STACK_VARIABLE: {
+#ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(address, _stack_size, NULL);
+#endif
return &p_stack[address];
} break;
case ADDR_TYPE_GLOBAL: {
-
+#ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), NULL);
-
+#endif
return &GDScriptLanguage::get_singleton()->get_global_array()[address];
} break;
case ADDR_TYPE_NIL: {
@@ -161,8 +170,71 @@ static String _get_var_type(const Variant *p_type) {
return basestr;
}
+#if defined(__GNUC__) && !defined(__clang__)
+#define OPCODES_TABLE \
+ static const void *switch_table_ops[] = { \
+ &&OPCODE_OPERATOR, \
+ &&OPCODE_EXTENDS_TEST, \
+ &&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_CONSTRUCT, \
+ &&OPCODE_CONSTRUCT_ARRAY, \
+ &&OPCODE_CONSTRUCT_DICTIONARY, \
+ &&OPCODE_CALL, \
+ &&OPCODE_CALL_RETURN, \
+ &&OPCODE_CALL_BUILT_IN, \
+ &&OPCODE_CALL_SELF, \
+ &&OPCODE_CALL_SELF_BASE, \
+ &&OPCODE_YIELD, \
+ &&OPCODE_YIELD_SIGNAL, \
+ &&OPCODE_YIELD_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 \
+ };
+
+#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 GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state) {
+ OPCODES_TABLE;
+
if (!_code_ptr) {
return Variant();
@@ -271,16 +343,26 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
if (ScriptDebugger::get_singleton())
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; \
+ } else \
+ _err_error_exists = false; \
+ }
+
#define CHECK_SPACE(m_space) \
- ERR_BREAK((ip + m_space) > _code_size)
+ 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, _class, self, stack, err_text); \
- if (!m_v) \
- break;
+ 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; \
@@ -302,32 +384,36 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#endif
bool exit_ok = false;
- while (ip < _code_size) {
-
+#ifdef DEBUG_ENABLED
+ OPCODE_WHILE(ip < _code_size) {
int last_opcode = _code_ptr[ip];
- switch (_code_ptr[ip]) {
+#else
+ OPCODE_WHILE(true) {
+#endif
- case OPCODE_OPERATOR: {
+ OPCODE_SWITCH(_code_ptr[ip]) {
+
+ OPCODE(OPCODE_OPERATOR) {
CHECK_SPACE(5);
bool valid;
Variant::Operator op = (Variant::Operator)_code_ptr[ip + 1];
- ERR_BREAK(op >= Variant::OP_MAX);
+ 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
-
- if (!valid) {
#ifdef DEBUG_ENABLED
+ if (!valid) {
if (ret.get_type() == Variant::STRING) {
//return a string when invalid with the error
@@ -336,17 +422,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
} 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) + "'.";
}
-#endif
- break;
+ OPCODE_BREAK;
}
-#ifdef DEBUG_ENABLED
*dst = ret;
#endif
-
ip += 5;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_EXTENDS_TEST: {
+ OPCODE(OPCODE_EXTENDS_TEST) {
CHECK_SPACE(4);
@@ -355,19 +438,17 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(dst, 3);
#ifdef DEBUG_ENABLED
-
if (a->get_type() != Variant::OBJECT || a->operator Object *() == NULL) {
err_text = "Left operand of 'is' is not an instance of anything.";
- break;
+ OPCODE_BREAK;
}
if (b->get_type() != Variant::OBJECT || b->operator Object *() == NULL) {
err_text = "Right operand of 'is' is not a class.";
- break;
+ OPCODE_BREAK;
}
#endif
-
Object *obj_A = *a;
Object *obj_B = *b;
@@ -399,20 +480,21 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GDNativeClass *nc = Object::cast_to<GDNativeClass>(obj_B);
+#ifdef DEBUG_ENABLED
if (!nc) {
err_text = "Right operand of 'is' is not a class (type: '" + obj_B->get_class() + "').";
- break;
+ OPCODE_BREAK;
}
-
+#endif
extends_ok = ClassDB::is_parent_class(obj_A->get_class_name(), nc->get_name());
}
*dst = extends_ok;
ip += 4;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_SET: {
+ OPCODE(OPCODE_SET) {
CHECK_SPACE(3);
@@ -423,6 +505,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
bool valid;
dst->set(*index, *value, &valid);
+#ifdef DEBUG_ENABLED
if (!valid) {
String v = index->operator String();
if (v != "") {
@@ -431,13 +514,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
v = "of type '" + _get_var_type(index) + "'";
}
err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "').";
- break;
+ OPCODE_BREAK;
}
-
+#endif
ip += 4;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_GET: {
+ OPCODE(OPCODE_GET) {
CHECK_SPACE(3);
@@ -453,6 +536,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = src->get(*index, &valid);
#endif
+#ifdef DEBUG_ENABLED
if (!valid) {
String v = index->operator String();
if (v != "") {
@@ -461,15 +545,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
v = "of type '" + _get_var_type(index) + "'";
}
err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "').";
- break;
+ OPCODE_BREAK;
}
-#ifdef DEBUG_ENABLED
*dst = ret;
#endif
ip += 4;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_SET_NAMED: {
+ OPCODE(OPCODE_SET_NAMED) {
CHECK_SPACE(3);
@@ -478,22 +561,23 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int indexname = _code_ptr[ip + 2];
- ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ 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) + "').";
- break;
+ OPCODE_BREAK;
}
-
+#endif
ip += 4;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_GET_NAMED: {
+ OPCODE(OPCODE_GET_NAMED) {
CHECK_SPACE(4);
@@ -502,7 +586,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int indexname = _code_ptr[ip + 2];
- ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
const StringName *index = &_global_names_ptr[indexname];
bool valid;
@@ -513,26 +597,25 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#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() + "()' ?";
} else {
err_text = "Invalid get index '" + index->operator String() + "' (on base: '" + _get_var_type(src) + "').";
}
- break;
+ OPCODE_BREAK;
}
-#ifdef DEBUG_ENABLED
*dst = ret;
#endif
ip += 4;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_SET_MEMBER: {
+ OPCODE(OPCODE_SET_MEMBER) {
CHECK_SPACE(3);
int indexname = _code_ptr[ip + 1];
- ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
const StringName *index = &_global_names_ptr[indexname];
GET_VARIANT_PTR(src, 2);
@@ -541,20 +624,20 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#ifdef DEBUG_ENABLED
if (!ok) {
err_text = "Internal error setting property: " + String(*index);
- break;
+ OPCODE_BREAK;
} else if (!valid) {
err_text = "Error setting property '" + String(*index) + "' with value of type " + Variant::get_type_name(src->get_type()) + ".";
- break;
+ OPCODE_BREAK;
}
#endif
ip += 3;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_GET_MEMBER: {
+ OPCODE(OPCODE_GET_MEMBER) {
CHECK_SPACE(3);
int indexname = _code_ptr[ip + 1];
- ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
+ GD_ERR_BREAK(indexname < 0 || indexname >= _global_names_count);
const StringName *index = &_global_names_ptr[indexname];
GET_VARIANT_PTR(dst, 2);
bool ok = ClassDB::get_property(p_instance->owner, *index, *dst);
@@ -562,13 +645,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#ifdef DEBUG_ENABLED
if (!ok) {
err_text = "Internal error getting property: " + String(*index);
- break;
+ OPCODE_BREAK;
}
#endif
ip += 3;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_ASSIGN: {
+ OPCODE(OPCODE_ASSIGN) {
CHECK_SPACE(3);
GET_VARIANT_PTR(dst, 1);
@@ -577,9 +660,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = *src;
ip += 3;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_ASSIGN_TRUE: {
+ OPCODE(OPCODE_ASSIGN_TRUE) {
CHECK_SPACE(2);
GET_VARIANT_PTR(dst, 1);
@@ -587,9 +670,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = true;
ip += 2;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_ASSIGN_FALSE: {
+ OPCODE(OPCODE_ASSIGN_FALSE) {
CHECK_SPACE(2);
GET_VARIANT_PTR(dst, 1);
@@ -597,9 +680,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = false;
ip += 2;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_CONSTRUCT: {
+ OPCODE(OPCODE_CONSTRUCT) {
CHECK_SPACE(2);
Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
@@ -615,17 +698,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
Variant::CallError err;
*dst = Variant::construct(t, (const Variant **)argptrs, argc, err);
+#ifdef DEBUG_ENABLED
if (err.error != Variant::CallError::CALL_OK) {
err_text = _get_call_error(err, "'" + Variant::get_type_name(t) + "' constructor", (const Variant **)argptrs);
- break;
+ OPCODE_BREAK;
}
+#endif
ip += 4 + argc;
//construct a basic type
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_CONSTRUCT_ARRAY: {
+ OPCODE(OPCODE_CONSTRUCT_ARRAY) {
CHECK_SPACE(1);
int argc = _code_ptr[ip + 1];
@@ -643,9 +728,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = array;
ip += 3 + argc;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_CONSTRUCT_DICTIONARY: {
+ OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
CHECK_SPACE(1);
int argc = _code_ptr[ip + 1];
@@ -665,10 +750,10 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = dict;
ip += 3 + argc * 2;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_CALL_RETURN:
- case OPCODE_CALL: {
+ OPCODE(OPCODE_CALL_RETURN)
+ OPCODE(OPCODE_CALL) {
CHECK_SPACE(4);
bool call_ret = _code_ptr[ip] == OPCODE_CALL_RETURN;
@@ -677,10 +762,10 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(base, 2);
int nameg = _code_ptr[ip + 3];
- ERR_BREAK(nameg < 0 || nameg >= _global_names_count);
+ GD_ERR_BREAK(nameg < 0 || nameg >= _global_names_count);
const StringName *methodname = &_global_names_ptr[nameg];
- ERR_BREAK(argc < 0);
+ GD_ERR_BREAK(argc < 0);
ip += 4;
CHECK_SPACE(argc + 1);
Variant **argptrs = call_args;
@@ -711,7 +796,6 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
}
-#endif
if (err.error != Variant::CallError::CALL_OK) {
@@ -731,29 +815,30 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
if (base->is_ref()) {
err_text = "Attempted to free a reference.";
- break;
+ OPCODE_BREAK;
} else if (base->get_type() == Variant::OBJECT) {
err_text = "Attempted to free a locked object (calling or emitting).";
- break;
+ OPCODE_BREAK;
}
}
}
err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
- break;
+ OPCODE_BREAK;
}
+#endif
//_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);
ip += argc + 1;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_CALL_BUILT_IN: {
+ OPCODE(OPCODE_CALL_BUILT_IN) {
CHECK_SPACE(4);
GDFunctions::Function func = GDFunctions::Function(_code_ptr[ip + 1]);
int argc = _code_ptr[ip + 2];
- ERR_BREAK(argc < 0);
+ GD_ERR_BREAK(argc < 0);
ip += 3;
CHECK_SPACE(argc + 1);
@@ -770,6 +855,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GDFunctions::call(func, (const Variant **)argptrs, argc, *dst, err);
+#ifdef DEBUG_ENABLED
if (err.error != Variant::CallError::CALL_OK) {
String methodstr = GDFunctions::get_func_name(func);
@@ -779,25 +865,26 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
} else {
err_text = _get_call_error(err, "built-in function '" + methodstr + "'", (const Variant **)argptrs);
}
- break;
+ OPCODE_BREAK;
}
+#endif
ip += argc + 1;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_CALL_SELF: {
+ OPCODE(OPCODE_CALL_SELF) {
- break;
+ OPCODE_BREAK;
}
- case OPCODE_CALL_SELF_BASE: {
+ OPCODE(OPCODE_CALL_SELF_BASE) {
CHECK_SPACE(2);
int self_fun = _code_ptr[ip + 1];
-#ifdef DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
if (self_fun < 0 || self_fun >= _global_names_count) {
err_text = "compiler bug, function name not found";
- break;
+ OPCODE_BREAK;
}
#endif
const StringName *methodname = &_global_names_ptr[self_fun];
@@ -857,14 +944,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
String methodstr = *methodname;
err_text = _get_call_error(err, "function '" + methodstr + "'", (const Variant **)argptrs);
- break;
+ OPCODE_BREAK;
}
ip += 4 + argc;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_YIELD:
- case OPCODE_YIELD_SIGNAL: {
+ OPCODE(OPCODE_YIELD)
+ OPCODE(OPCODE_YIELD_SIGNAL) {
int ipofs = 1;
if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) {
@@ -898,133 +985,125 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
retvalue = gdfs;
if (_code_ptr[ip] == OPCODE_YIELD_SIGNAL) {
+ //do the oneshot connect
GET_VARIANT_PTR(argobj, 1);
GET_VARIANT_PTR(argname, 2);
- //do the oneshot connect
+#ifdef DEBUG_ENABLED
if (argobj->get_type() != Variant::OBJECT) {
err_text = "First argument of yield() not of type object.";
- break;
+ OPCODE_BREAK;
}
if (argname->get_type() != Variant::STRING) {
err_text = "Second argument of yield() not a string (for signal name).";
- break;
+ OPCODE_BREAK;
}
+#endif
Object *obj = argobj->operator Object *();
String signal = argname->operator String();
#ifdef DEBUG_ENABLED
if (!obj) {
err_text = "First argument of yield() is null.";
- break;
+ OPCODE_BREAK;
}
if (ScriptDebugger::get_singleton()) {
if (!ObjectDB::instance_validate(obj)) {
err_text = "First argument of yield() is a previously freed instance.";
- break;
+ OPCODE_BREAK;
}
}
if (signal.length() == 0) {
err_text = "Second argument of yield() is an empty string (for signal name).";
- break;
+ OPCODE_BREAK;
}
#endif
Error err = obj->connect(signal, gdfs.ptr(), "_signal_callback", varray(gdfs), Object::CONNECT_ONESHOT);
+#ifdef DEBUG_ENABLED
if (err != OK) {
err_text = "Error connecting to signal: " + signal + " during yield().";
- break;
+ OPCODE_BREAK;
}
+#endif
}
exit_ok = true;
- break;
+ OPCODE_BREAK;
}
- case OPCODE_YIELD_RESUME: {
+ OPCODE(OPCODE_YIELD_RESUME) {
CHECK_SPACE(2);
+#ifdef DEBUG_ENABLED
if (!p_state) {
err_text = ("Invalid Resume (bug?)");
- break;
+ OPCODE_BREAK;
}
+#endif
GET_VARIANT_PTR(result, 1);
*result = p_state->result;
ip += 2;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_JUMP: {
+ OPCODE(OPCODE_JUMP) {
CHECK_SPACE(2);
int to = _code_ptr[ip + 1];
- ERR_BREAK(to < 0 || to > _code_size);
+ GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_JUMP_IF: {
+ OPCODE(OPCODE_JUMP_IF) {
CHECK_SPACE(3);
GET_VARIANT_PTR(test, 1);
- bool valid;
- bool result = test->booleanize(valid);
-#ifdef DEBUG_ENABLED
- if (!valid) {
+ bool result = test->booleanize();
- err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
- break;
- }
-#endif
if (result) {
int to = _code_ptr[ip + 2];
- ERR_BREAK(to < 0 || to > _code_size);
+ GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
- continue;
+ DISPATCH_OPCODE;
}
ip += 3;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_JUMP_IF_NOT: {
+ OPCODE(OPCODE_JUMP_IF_NOT) {
CHECK_SPACE(3);
GET_VARIANT_PTR(test, 1);
- bool valid;
- bool result = test->booleanize(valid);
-#ifdef DEBUG_ENABLED
- if (!valid) {
+ bool result = test->booleanize();
- err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
- break;
- }
-#endif
if (!result) {
int to = _code_ptr[ip + 2];
- ERR_BREAK(to < 0 || to > _code_size);
+ GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
- continue;
+ DISPATCH_OPCODE;
}
ip += 3;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_JUMP_TO_DEF_ARGUMENT: {
+ OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) {
CHECK_SPACE(2);
ip = _default_arg_ptr[defarg];
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_RETURN: {
+ OPCODE(OPCODE_RETURN) {
CHECK_SPACE(2);
GET_VARIANT_PTR(r, 1);
retvalue = *r;
exit_ok = true;
- break;
+ OPCODE_BREAK;
}
- case OPCODE_ITERATE_BEGIN: {
+ OPCODE(OPCODE_ITERATE_BEGIN) {
CHECK_SPACE(8); //space for this a regular iterate
@@ -1033,27 +1112,30 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
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()) + "'.";
- break;
+ OPCODE_BREAK;
}
+#endif
int jumpto = _code_ptr[ip + 3];
- ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
- continue;
+ DISPATCH_OPCODE;
}
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()) + "'.";
- break;
+ OPCODE_BREAK;
}
-
+#endif
ip += 5; //skip regular iterate which is always next
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_ITERATE: {
+ OPCODE(OPCODE_ITERATE) {
CHECK_SPACE(4);
@@ -1062,61 +1144,56 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
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?).";
- break;
+ OPCODE_BREAK;
}
+#endif
int jumpto = _code_ptr[ip + 3];
- ERR_BREAK(jumpto < 0 || jumpto > _code_size);
+ GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
- continue;
+ DISPATCH_OPCODE;
}
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?).";
- break;
+ OPCODE_BREAK;
}
-
+#endif
ip += 5; //loop again
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_ASSERT: {
+ OPCODE(OPCODE_ASSERT) {
CHECK_SPACE(2);
GET_VARIANT_PTR(test, 1);
#ifdef DEBUG_ENABLED
- bool valid;
- bool result = test->booleanize(valid);
-
- if (!valid) {
-
- err_text = "cannot evaluate conditional expression of type: " + Variant::get_type_name(test->get_type());
- break;
- }
+ bool result = test->booleanize();
if (!result) {
err_text = "Assertion failed.";
- break;
+ OPCODE_BREAK;
}
#endif
-
ip += 2;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_BREAKPOINT: {
+ OPCODE(OPCODE_BREAKPOINT) {
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton()) {
GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement", true);
}
#endif
ip += 1;
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_LINE: {
+ OPCODE(OPCODE_LINE) {
CHECK_SPACE(2);
line = _code_ptr[ip + 1];
@@ -1143,22 +1220,26 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ScriptDebugger::get_singleton()->line_poll();
}
- continue;
+ DISPATCH_OPCODE;
}
- case OPCODE_END: {
+ OPCODE(OPCODE_END) {
exit_ok = true;
- break;
+ OPCODE_BREAK;
}
+#if 0
default: {
err_text = "Illegal opcode " + itos(_code_ptr[ip]) + " at address " + itos(ip);
- break;
+ OPCODE_BREAK;
}
+#endif
}
+ OPCODES_END
+#ifdef DEBUG_ENABLED
if (exit_ok)
- break;
+ OPCODE_OUT;
//error
// function, file, line, error, explanation
String err_file;
@@ -1182,9 +1263,11 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
_err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
}
- break;
+#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;
@@ -1495,7 +1578,7 @@ void GDFunctionState::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_valid", "extended_check"), &GDFunctionState::is_valid, DEFVAL(false));
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &GDFunctionState::_signal_callback, MethodInfo("_signal_callback"));
- ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result")));
+ ADD_SIGNAL(MethodInfo("completed", PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
}
GDFunctionState::GDFunctionState() {
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index 34d01c6beb..b43ec409a1 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.cpp
@@ -83,6 +83,8 @@ const char *GDFunctions::get_func_name(Function p_func) {
"rad2deg",
"linear2db",
"db2linear",
+ "wrapi",
+ "wrapf",
"max",
"min",
"clamp",
@@ -405,6 +407,14 @@ void GDFunctions::call(Function p_func, const Variant **p_args, int p_arg_count,
VALIDATE_ARG_NUM(0);
r_ret = Math::db2linear((double)*p_args[0]);
} 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) {
@@ -1285,6 +1295,8 @@ bool GDFunctions::is_deterministic(Function p_func) {
case MATH_RAD2DEG:
case MATH_LINEAR2DB:
case MATH_DB2LINEAR:
+ case MATH_WRAP:
+ case MATH_WRAPF:
case LOGIC_MAX:
case LOGIC_MIN:
case LOGIC_CLAMP:
@@ -1513,6 +1525,16 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::REAL;
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::REAL, "value"), PropertyInfo(Variant::REAL, "min"), PropertyInfo(Variant::REAL, "max"));
+ mi.return_val.type = Variant::REAL;
+ return mi;
+ } break;
case LOGIC_MAX: {
MethodInfo mi("max", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b"));
mi.return_val.type = Variant::REAL;
diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h
index a568c8f1cf..0de09f2e71 100644
--- a/modules/gdscript/gd_functions.h
+++ b/modules/gdscript/gd_functions.h
@@ -75,6 +75,8 @@ public:
MATH_RAD2DEG,
MATH_LINEAR2DB,
MATH_DB2LINEAR,
+ MATH_WRAP,
+ MATH_WRAPF,
LOGIC_MAX,
LOGIC_MIN,
LOGIC_CLAMP,
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 72c3f9612a..94385dc0d0 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -1699,7 +1699,7 @@ GDParser::Node *GDParser::_reduce_expression(Node *p_node, bool p_to_const) {
_REDUCE_BINARY(Variant::OP_ADD);
} break;
case OperatorNode::OP_SUB: {
- _REDUCE_BINARY(Variant::OP_SUBSTRACT);
+ _REDUCE_BINARY(Variant::OP_SUBTRACT);
} break;
case OperatorNode::OP_MUL: {
_REDUCE_BINARY(Variant::OP_MULTIPLY);
@@ -1906,7 +1906,8 @@ GDParser::PatternNode *GDParser::_parse_pattern(bool p_static) {
// all the constants like strings and numbers
default: {
Node *value = _parse_and_reduce_expression(pattern, p_static);
- if (error_set) {
+ if (!value) {
+ _set_error("Expect constant expression or variables in a pattern");
return NULL;
}
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index cf6529d5ae..3f3818ffb9 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -609,11 +609,6 @@ Error GDScript::reload(bool p_keep_state) {
return OK;
}
-String GDScript::get_node_type() const {
-
- return ""; // ?
-}
-
ScriptLanguage *GDScript::get_language() const {
return GDScriptLanguage::get_singleton();
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index 5e1a8b19ac..e0d142014a 100644
--- a/modules/gdscript/gd_script.h
+++ b/modules/gdscript/gd_script.h
@@ -172,7 +172,6 @@ public:
virtual Error reload(bool p_keep_state = false);
- virtual String get_node_type() const;
void set_script_path(const String &p_path) { path = p_path; } //because subclasses need a path too...
Error load_source_code(const String &p_path);
Error load_byte_code(const String &p_path);
@@ -386,6 +385,7 @@ public:
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const;
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 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 PoolStringArray &p_args) const;
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 3676570ec1..5b0fe56f25 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GridMap" inherits="Spatial" category="Core" version="3.0.alpha.custom_build">
<brief_description>
+ Node for 3D tile-based maps.
</brief_description>
<description>
+ GridMap lets you place meshes on a grid interactively. It works both from the editor and can help you create in-game level editors.
+ GridMaps use a [MeshLibrary] which contain a list of tiles: meshes with materials plus optional collisions and extra elements.
+ A GridMap contains a collection of cells. Each grid cell refers to a [MeshLibrary] item. All cells in the map have the same dimensions.
+ A GridMap is split into a sparse collection of octants for efficient rendering and physics processing. Every octant has the same dimensions and can contain several cells.
</description>
<tutorials>
</tutorials>
@@ -13,6 +18,7 @@
<return type="void">
</return>
<description>
+ Clear all cells.
</description>
</method>
<method name="get_cell_item" qualifiers="const">
@@ -25,6 +31,7 @@
<argument index="2" name="z" type="int">
</argument>
<description>
+ The [MeshLibrary] item index located at the grid-based X, Y and Z coordinates. If the cell is empty, [INVALID_CELL_ITEM] will be returned.
</description>
</method>
<method name="get_cell_item_orientation" qualifiers="const">
@@ -37,48 +44,75 @@
<argument index="2" name="z" type="int">
</argument>
<description>
+ The orientation of the cell at the grid-based X, Y and Z coordinates. -1 is retuned if the cell is empty.
</description>
</method>
<method name="get_cell_size" qualifiers="const">
<return type="Vector3">
</return>
<description>
+ The dimensions of the grid's cells.
</description>
</method>
<method name="get_center_x" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns whether or not grid items are centered on the X axis.
</description>
</method>
<method name="get_center_y" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns whether or not grid items are centered on the Y axis.
</description>
</method>
<method name="get_center_z" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns whether or not grid items are centered on the Z axis.
</description>
</method>
<method name="get_meshes">
<return type="Array">
</return>
<description>
+ Array of [Transform] and [Mesh] references corresponding to the non empty cells in the grid. The transforms are specified in world space.
</description>
</method>
<method name="get_octant_size" qualifiers="const">
<return type="int">
</return>
<description>
+ The size of each octant measured in number of cells. This applies to all three axis.
</description>
</method>
<method name="get_theme" qualifiers="const">
<return type="MeshLibrary">
</return>
<description>
+ The assigned [MeshLibrary].
+ </description>
+ </method>
+ <method name="get_used_cells" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Array of [Vector3] with the non empty cell coordinates in the grid map.
+ </description>
+ </method>
+ <method name="map_to_world" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="x" type="int">
+ </argument>
+ <argument index="1" name="y" type="int">
+ </argument>
+ <argument index="2" name="z" type="int">
+ </argument>
+ <description>
</description>
</method>
<method name="resource_changed">
@@ -103,6 +137,9 @@
<argument index="4" name="orientation" type="int" default="0">
</argument>
<description>
+ Set the mesh index for the cell referenced by its grid-based X, Y and Z coordinates.
+ A negative item index will clear the cell.
+ Optionally, the item's orientation can be passed.
</description>
</method>
<method name="set_cell_size">
@@ -111,6 +148,7 @@
<argument index="0" name="size" type="Vector3">
</argument>
<description>
+ Sets the height, width and depth of the grid's cells.
</description>
</method>
<method name="set_center_x">
@@ -119,6 +157,7 @@
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ Set grid items to be centered on the X axis. By default it is enabled.
</description>
</method>
<method name="set_center_y">
@@ -127,6 +166,7 @@
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ Set grid items to be centered on the Y axis. By default it is enabled.
</description>
</method>
<method name="set_center_z">
@@ -135,6 +175,7 @@
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ Set grid items to be centered on the Z axis. By default it is enabled.
</description>
</method>
<method name="set_clip">
@@ -157,6 +198,7 @@
<argument index="0" name="size" type="int">
</argument>
<description>
+ Sets the size for each octant measured in number of cells. This applies to all three axis.
</description>
</method>
<method name="set_theme">
@@ -165,11 +207,21 @@
<argument index="0" name="theme" type="MeshLibrary">
</argument>
<description>
+ Sets the collection of meshes for the map.
+ </description>
+ </method>
+ <method name="world_to_map" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="pos" type="Vector3">
+ </argument>
+ <description>
</description>
</method>
</methods>
<constants>
<constant name="INVALID_CELL_ITEM" value="-1" enum="">
+ Invalid cell item that can be used in [method set_cell_item] to clear cells (or represent an empty cell in [method get_cell_item]).
</constant>
</constants>
</class>
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 4f7545a11d..cb14a5ee9c 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -333,6 +333,23 @@ int GridMap::get_cell_item_orientation(int p_x, int p_y, int p_z) const {
return cell_map[key].rot;
}
+Vector3 GridMap::world_to_map(const Vector3 &p_world_pos) const {
+ Vector3 map_pos = p_world_pos / cell_size;
+ map_pos.x = floor(map_pos.x);
+ map_pos.y = floor(map_pos.y);
+ map_pos.z = floor(map_pos.z);
+ return map_pos;
+}
+
+Vector3 GridMap::map_to_world(int p_x, int p_y, int p_z) const {
+ Vector3 offset = _get_offset();
+ Vector3 world_pos(
+ p_x * cell_size.x + offset.x,
+ p_y * cell_size.y + offset.y,
+ p_z * cell_size.z + offset.z);
+ return world_pos;
+}
+
void GridMap::_octant_transform(const OctantKey &p_key) {
ERR_FAIL_COND(!octant_map.has(p_key));
@@ -407,7 +424,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
//print_line("OCTANT, CELLS: "+itos(ii.cells.size()));
Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z);
- Vector3 ofs(cell_size.x * 0.5 * int(center_x), cell_size.y * 0.5 * int(center_y), cell_size.z * 0.5 * int(center_z));
+ Vector3 ofs = _get_offset();
Transform xform;
@@ -754,6 +771,9 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cell_item", "x", "y", "z"), &GridMap::get_cell_item);
ClassDB::bind_method(D_METHOD("get_cell_item_orientation", "x", "y", "z"), &GridMap::get_cell_item_orientation);
+ ClassDB::bind_method(D_METHOD("world_to_map", "pos"), &GridMap::world_to_map);
+ ClassDB::bind_method(D_METHOD("map_to_world", "x", "y", "z"), &GridMap::map_to_world);
+
//ClassDB::bind_method(D_METHOD("_recreate_octants"),&GridMap::_recreate_octants);
ClassDB::bind_method(D_METHOD("_update_octants_callback"), &GridMap::_update_octants_callback);
ClassDB::bind_method(D_METHOD("resource_changed", "resource"), &GridMap::resource_changed);
@@ -769,6 +789,8 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &GridMap::clear);
+ ClassDB::bind_method(D_METHOD("get_used_cells"), &GridMap::get_used_cells);
+
ClassDB::bind_method(D_METHOD("get_meshes"), &GridMap::get_meshes);
BIND_CONSTANT(INVALID_CELL_ITEM);
@@ -799,7 +821,7 @@ void GridMap::set_clip(bool p_enabled, bool p_clip_above, int p_floor, Vector3::
void GridMap::set_cell_scale(float p_scale) {
cell_scale = p_scale;
- _queue_octants_dirty();
+ _recreate_octant_data();
}
float GridMap::get_cell_scale() const {
@@ -807,12 +829,25 @@ float GridMap::get_cell_scale() const {
return cell_scale;
}
+Array GridMap::get_used_cells() const {
+
+ Array a;
+ a.resize(cell_map.size());
+ int i = 0;
+ for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
+ Vector3 p(E->key().x, E->key().y, E->key().z);
+ a[i++] = p;
+ }
+
+ return a;
+}
+
Array GridMap::get_meshes() {
if (theme.is_null())
return Array();
- Vector3 ofs(cell_size.x * 0.5 * int(center_x), cell_size.y * 0.5 * int(center_y), cell_size.z * 0.5 * int(center_z));
+ Vector3 ofs = _get_offset();
Array meshes;
for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
@@ -842,6 +877,13 @@ Array GridMap::get_meshes() {
return meshes;
}
+Vector3 GridMap::_get_offset() const {
+ return Vector3(
+ cell_size.x * 0.5 * int(center_x),
+ cell_size.y * 0.5 * int(center_y),
+ cell_size.z * 0.5 * int(center_z));
+}
+
GridMap::GridMap() {
cell_size = Vector3(2, 2, 2);
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index eb1b215696..5bfdf1dac3 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -184,6 +184,8 @@ class GridMap : public Spatial {
void _clear_internal();
+ Vector3 _get_offset() const;
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -218,11 +220,16 @@ public:
int get_cell_item(int p_x, int p_y, int p_z) const;
int get_cell_item_orientation(int p_x, int p_y, int p_z) const;
+ Vector3 world_to_map(const Vector3 &p_pos) const;
+ Vector3 map_to_world(int p_x, int p_y, int p_z) const;
+
void set_clip(bool p_enabled, bool p_clip_above = true, int p_floor = 0, Vector3::Axis p_axis = Vector3::AXIS_X);
void set_cell_scale(float p_scale);
float get_cell_scale() const;
+ Array get_used_cells() const;
+
Array get_meshes();
void clear();
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 92d88207b3..08ac624504 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -38,7 +38,6 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
String header = f->get_token();
- print_line("HEADER: " + header);
ERR_FAIL_COND_V(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED);
while (true) {
@@ -64,8 +63,6 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
int width = f->get_line().to_int();
- print_line("HDR w: " + itos(width) + " h:" + itos(height));
-
PoolVector<uint8_t> imgdata;
imgdata.resize(height * width * sizeof(uint32_t));
@@ -102,7 +99,6 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
len <<= 8;
len |= f->get_8();
- print_line("line: " + itos(len));
if (len != width) {
ERR_EXPLAIN("invalid decoded scanline length, corrupt HDR");
ERR_FAIL_V(ERR_FILE_CORRUPT);
diff --git a/modules/mobile_vr/SCsub b/modules/mobile_vr/SCsub
new file mode 100644
index 0000000000..b4e2edcca1
--- /dev/null
+++ b/modules/mobile_vr/SCsub
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+import os
+import methods
+
+Import('env')
+Import('env_modules')
+
+env_mobile_vr = env_modules.Clone()
+
+env_mobile_vr.add_source_files(env.modules_sources, '*.cpp')
+
+SConscript("shaders/SCsub")
diff --git a/modules/mobile_vr/config.py b/modules/mobile_vr/config.py
new file mode 100644
index 0000000000..cf96c66125
--- /dev/null
+++ b/modules/mobile_vr/config.py
@@ -0,0 +1,12 @@
+def can_build(platform):
+ # should probably change this to only be true on iOS and Android
+ return True
+
+def configure(env):
+ pass
+
+def get_doc_classes():
+ return ["MobileVRInterface"]
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
new file mode 100644
index 0000000000..c945a99a9a
--- /dev/null
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="MobileVRInterface" inherits="ARVRInterface" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ Generic mobile VR implementation
+ </brief_description>
+ <description>
+ This is a generic mobile VR implementation where you need to provide details about the phone and HMD used. It does not rely on any existing framework. This is the most basic interface we have. For the best effect you do need a mobile phone with a gyroscope and accelerometer.
+ Note that even though there is no positional tracking the camera will assume the headset is at a height of 1.85 meters.
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ <method name="get_display_to_lens" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the distance between the display and the lens.
+ </description>
+ </method>
+ <method name="get_display_width" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return the width of the LCD screen of the device.
+ </description>
+ </method>
+ <method name="get_iod" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the interocular distance.
+ </description>
+ </method>
+ <method name="get_k1" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the k1 lens constant.
+ </description>
+ </method>
+ <method name="get_k2" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Retuns the k2 lens constant
+ </description>
+ </method>
+ <method name="get_oversample" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the oversampling setting.
+ </description>
+ </method>
+ <method name="set_display_to_lens">
+ <return type="void">
+ </return>
+ <argument index="0" name="display_to_lens" type="float">
+ </argument>
+ <description>
+ Sets the distance between display and the lens.
+ </description>
+ </method>
+ <method name="set_display_width">
+ <return type="void">
+ </return>
+ <argument index="0" name="display_width" type="float">
+ </argument>
+ <description>
+ Sets the width of the LCD screen of the device.
+ </description>
+ </method>
+ <method name="set_iod">
+ <return type="void">
+ </return>
+ <argument index="0" name="iod" type="float">
+ </argument>
+ <description>
+ Sets the interocular distance.
+ </description>
+ </method>
+ <method name="set_k1">
+ <return type="void">
+ </return>
+ <argument index="0" name="k" type="float">
+ </argument>
+ <description>
+ Sets the k1 lens constant.
+ </description>
+ </method>
+ <method name="set_k2">
+ <return type="void">
+ </return>
+ <argument index="0" name="k" type="float">
+ </argument>
+ <description>
+ Sets the k2 lens constant.
+ </description>
+ </method>
+ <method name="set_oversample">
+ <return type="void">
+ </return>
+ <argument index="0" name="oversample" type="float">
+ </argument>
+ <description>
+ Sets the oversampling setting.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="display_to_lens" type="float" setter="set_display_to_lens" getter="get_display_to_lens">
+ The distance between the display and the lenses inside of the device in centimeters.
+ </member>
+ <member name="display_width" type="float" setter="set_display_width" getter="get_display_width">
+ The width of the display in centimeters.
+ </member>
+ <member name="iod" type="float" setter="set_iod" getter="get_iod">
+ The interocular distance, also known as the interpupillary distance. The distance between the pupils of the left and right eye.
+ </member>
+ <member name="k1" type="float" setter="set_k1" getter="get_k1">
+ The k1 lens factor is one of the two constants that define the strength of the lens used and directly influences the lens distortion effect.
+ </member>
+ <member name="k2" type="float" setter="set_k2" getter="get_k2">
+ The k2 lens factor, see k1.
+ </member>
+ <member name="oversample" type="float" setter="set_oversample" getter="get_oversample">
+ The oversample setting. Because of the lens distortion we have to render our buffers at a higher resolution then the screen can natively handle. A value between 1.5 and 2.0 often provides good results but at the cost of performance.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/mobile_vr/mobile_interface.cpp b/modules/mobile_vr/mobile_interface.cpp
new file mode 100644
index 0000000000..eb87bb2cf0
--- /dev/null
+++ b/modules/mobile_vr/mobile_interface.cpp
@@ -0,0 +1,504 @@
+/*************************************************************************/
+/* mobile_interface.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "mobile_interface.h"
+#include "core/os/input.h"
+#include "core/os/os.h"
+#include "servers/visual/visual_server_global.h"
+
+StringName MobileVRInterface::get_name() const {
+ return "Native mobile";
+};
+
+int MobileVRInterface::get_capabilities() const {
+ return ARVRInterface::ARVR_STEREO;
+};
+
+Vector3 MobileVRInterface::scale_magneto(const Vector3 &p_magnetometer) {
+ // Our magnetometer doesn't give us nice clean data.
+ // Well it may on Mac OS X because we're getting a calibrated value in the current implementation but Android we're getting raw data.
+ // This is a fairly simple adjustment we can do to correct for the magnetometer data being elliptical
+
+ Vector3 mag_raw = p_magnetometer;
+ Vector3 mag_scaled = p_magnetometer;
+
+ // update our variables every x frames
+ if (mag_count > 20) {
+ mag_current_min = mag_next_min;
+ mag_current_max = mag_next_max;
+ mag_count = 0;
+ } else {
+ mag_count++;
+ };
+
+ // adjust our min and max
+ if (mag_raw.x > mag_next_max.x) mag_next_max.x = mag_raw.x;
+ if (mag_raw.y > mag_next_max.y) mag_next_max.y = mag_raw.y;
+ if (mag_raw.z > mag_next_max.z) mag_next_max.z = mag_raw.z;
+
+ if (mag_raw.x < mag_next_min.x) mag_next_min.x = mag_raw.x;
+ if (mag_raw.y < mag_next_min.y) mag_next_min.y = mag_raw.y;
+ if (mag_raw.z < mag_next_min.z) mag_next_min.z = mag_raw.z;
+
+ // scale our x, y and z
+ if (!(mag_current_max.x - mag_current_min.x)) {
+ mag_raw.x -= (mag_current_min.x + mag_current_max.x) / 2.0;
+ mag_scaled.x = (mag_raw.x - mag_current_min.x) / ((mag_current_max.x - mag_current_min.x) * 2.0 - 1.0);
+ };
+
+ if (!(mag_current_max.y - mag_current_min.y)) {
+ mag_raw.y -= (mag_current_min.y + mag_current_max.y) / 2.0;
+ mag_scaled.y = (mag_raw.y - mag_current_min.y) / ((mag_current_max.y - mag_current_min.y) * 2.0 - 1.0);
+ };
+
+ if (!(mag_current_max.z - mag_current_min.z)) {
+ mag_raw.z -= (mag_current_min.z + mag_current_max.z) / 2.0;
+ mag_scaled.z = (mag_raw.z - mag_current_min.z) / ((mag_current_max.z - mag_current_min.z) * 2.0 - 1.0);
+ };
+
+ return mag_scaled;
+};
+
+Basis MobileVRInterface::combine_acc_mag(const Vector3 &p_grav, const Vector3 &p_magneto) {
+ // yup, stock standard cross product solution...
+ Vector3 up = -p_grav.normalized();
+
+ Vector3 magneto_east = up.cross(p_magneto.normalized()); // or is this west?, but should be horizon aligned now
+ magneto_east.normalize();
+
+ Vector3 magneto = up.cross(magneto_east); // and now we have a horizon aligned north
+ magneto.normalize();
+
+ // We use our gravity and magnetometer vectors to construct our matrix
+ Basis acc_mag_m3;
+ acc_mag_m3.elements[0] = -magneto_east;
+ acc_mag_m3.elements[1] = up;
+ acc_mag_m3.elements[2] = magneto;
+
+ return acc_mag_m3;
+};
+
+void MobileVRInterface::set_position_from_sensors() {
+ _THREAD_SAFE_METHOD_
+
+ // this is a helper function that attempts to adjust our transform using our 9dof sensors
+ // 9dof is a misleading marketing term coming from 3 accelerometer axis + 3 gyro axis + 3 magnetometer axis = 9 axis
+ // but in reality this only offers 3 dof (yaw, pitch, roll) orientation
+
+ uint64_t ticks = OS::get_singleton()->get_ticks_usec();
+ uint64_t ticks_elapsed = ticks - last_ticks;
+ float delta_time = (double)ticks_elapsed / 1000000.0;
+
+ // few things we need
+ Input *input = Input::get_singleton();
+ Vector3 down(0.0, -1.0, 0.0); // Down is Y negative
+ Vector3 north(0.0, 0.0, 1.0); // North is Z positive
+
+ // make copies of our inputs
+ Vector3 acc = input->get_accelerometer();
+ Vector3 gyro = input->get_gyroscope();
+ Vector3 grav = input->get_gravity();
+ Vector3 magneto = scale_magneto(input->get_magnetometer()); // this may be overkill on iOS because we're already getting a calibrated magnetometer reading
+
+ if (sensor_first) {
+ sensor_first = false;
+ } else {
+ acc = scrub(acc, last_accerometer_data, 2, 0.2);
+ magneto = scrub(magneto, last_magnetometer_data, 3, 0.3);
+ };
+
+ last_accerometer_data = acc;
+ last_magnetometer_data = magneto;
+
+ if (grav.length() < 0.1) {
+ // not ideal but use our accelerometer, this will contain shakey shakey user behaviour
+ // maybe look into some math but I'm guessing that if this isn't available, its because we lack the gyro sensor to actually work out
+ // what a stable gravity vector is
+ grav = acc;
+ if (grav.length() > 0.1) {
+ has_gyro = true;
+ };
+ } else {
+ has_gyro = true;
+ };
+
+ bool has_magneto = magneto.length() > 0.1;
+ bool has_grav = grav.length() > 0.1;
+
+#ifdef ANDROID_ENABLED
+ ///@TODO needs testing, i don't have a gyro, potentially can be removed depending on what comes out of issue #8101
+ // On Android x and z axis seem inverted
+ gyro.x = -gyro.x;
+ gyro.z = -gyro.z;
+ grav.x = -grav.x;
+ grav.z = -grav.z;
+ magneto.x = -magneto.x;
+ magneto.z = -magneto.z;
+#endif
+
+ if (has_gyro) {
+ // start with applying our gyro (do NOT smooth our gyro!)
+ Basis rotate;
+ rotate.rotate(orientation.get_axis(0), gyro.x * delta_time);
+ rotate.rotate(orientation.get_axis(1), gyro.y * delta_time);
+ rotate.rotate(orientation.get_axis(2), gyro.z * delta_time);
+ orientation = rotate * orientation;
+
+ tracking_state = ARVRInterface::ARVR_NORMAL_TRACKING;
+ };
+
+ ///@TODO improve this, the magnetometer is very fidgity sometimes flipping the axis for no apparent reason (probably a bug on my part)
+ // if you have a gyro + accelerometer that combo tends to be better then combining all three but without a gyro you need the magnetometer..
+ if (has_magneto && has_grav && !has_gyro) {
+ // convert to quaternions, easier to smooth those out
+ Quat transform_quat(orientation);
+ Quat acc_mag_quat(combine_acc_mag(grav, magneto));
+ transform_quat = transform_quat.slerp(acc_mag_quat, 0.1);
+ orientation = Basis(transform_quat);
+
+ tracking_state = ARVRInterface::ARVR_NORMAL_TRACKING;
+ } else if (has_grav) {
+ // use gravity vector to make sure down is down...
+ // transform gravity into our world space
+ grav.normalize();
+ Vector3 grav_adj = orientation.xform(grav);
+ float dot = grav_adj.dot(down);
+ if ((dot > -1.0) && (dot < 1.0)) {
+ // axis around which we have this rotation
+ Vector3 axis = grav_adj.cross(down);
+ axis.normalize();
+
+ Basis drift_compensation(axis, acos(dot) * delta_time * 10);
+ orientation = drift_compensation * orientation;
+ };
+ };
+
+ // JIC
+ orientation.orthonormalize();
+
+ last_ticks = ticks;
+};
+
+void MobileVRInterface::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_iod", "iod"), &MobileVRInterface::set_iod);
+ ClassDB::bind_method(D_METHOD("get_iod"), &MobileVRInterface::get_iod);
+
+ ClassDB::bind_method(D_METHOD("set_display_width", "display_width"), &MobileVRInterface::set_display_width);
+ ClassDB::bind_method(D_METHOD("get_display_width"), &MobileVRInterface::get_display_width);
+
+ ClassDB::bind_method(D_METHOD("set_display_to_lens", "display_to_lens"), &MobileVRInterface::set_display_to_lens);
+ ClassDB::bind_method(D_METHOD("get_display_to_lens"), &MobileVRInterface::get_display_to_lens);
+
+ ClassDB::bind_method(D_METHOD("set_oversample", "oversample"), &MobileVRInterface::set_oversample);
+ ClassDB::bind_method(D_METHOD("get_oversample"), &MobileVRInterface::get_oversample);
+
+ ClassDB::bind_method(D_METHOD("set_k1", "k"), &MobileVRInterface::set_k1);
+ ClassDB::bind_method(D_METHOD("get_k1"), &MobileVRInterface::get_k1);
+
+ ClassDB::bind_method(D_METHOD("set_k2", "k"), &MobileVRInterface::set_k2);
+ ClassDB::bind_method(D_METHOD("get_k2"), &MobileVRInterface::get_k2);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "iod", PROPERTY_HINT_RANGE, "4.0,10.0,0.1"), "set_iod", "get_iod");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "display_width", PROPERTY_HINT_RANGE, "5.0,25.0,0.1"), "set_display_width", "get_display_width");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "display_to_lens", PROPERTY_HINT_RANGE, "5.0,25.0,0.1"), "set_display_to_lens", "get_display_to_lens");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "oversample", PROPERTY_HINT_RANGE, "1.0,2.0,0.1"), "set_oversample", "get_oversample");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "k1", PROPERTY_HINT_RANGE, "0.1,10.0,0.0001"), "set_k1", "get_k1");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "k2", PROPERTY_HINT_RANGE, "0.1,10.0,0.0001"), "set_k2", "get_k2");
+}
+
+void MobileVRInterface::set_iod(const real_t p_iod) {
+ intraocular_dist = p_iod;
+};
+
+real_t MobileVRInterface::get_iod() const {
+ return intraocular_dist;
+};
+
+void MobileVRInterface::set_display_width(const real_t p_display_width) {
+ display_width = p_display_width;
+};
+
+real_t MobileVRInterface::get_display_width() const {
+ return display_width;
+};
+
+void MobileVRInterface::set_display_to_lens(const real_t p_display_to_lens) {
+ display_to_lens = p_display_to_lens;
+};
+
+real_t MobileVRInterface::get_display_to_lens() const {
+ return display_to_lens;
+};
+
+void MobileVRInterface::set_oversample(const real_t p_oversample) {
+ oversample = p_oversample;
+};
+
+real_t MobileVRInterface::get_oversample() const {
+ return oversample;
+};
+
+void MobileVRInterface::set_k1(const real_t p_k1) {
+ k1 = p_k1;
+};
+
+real_t MobileVRInterface::get_k1() const {
+ return k1;
+};
+
+void MobileVRInterface::set_k2(const real_t p_k2) {
+ k2 = p_k2;
+};
+
+real_t MobileVRInterface::get_k2() const {
+ return k2;
+};
+
+bool MobileVRInterface::is_stereo() {
+ // needs stereo...
+ return true;
+};
+
+bool MobileVRInterface::is_initialized() {
+ return (initialized);
+};
+
+bool MobileVRInterface::initialize() {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, false);
+
+ if (!initialized) {
+ // reset our sensor data and orientation
+ mag_count = 0;
+ has_gyro = false;
+ sensor_first = true;
+ mag_next_min = Vector3(10000, 10000, 10000);
+ mag_next_max = Vector3(-10000, -10000, -10000);
+ mag_current_min = Vector3(0, 0, 0);
+ mag_current_max = Vector3(0, 0, 0);
+
+ // reset our orientation
+ orientation = Basis();
+
+ // make this our primary interface
+ arvr_server->set_primary_interface(this);
+
+ last_ticks = OS::get_singleton()->get_ticks_usec();
+ ;
+ initialized = true;
+ };
+
+ return true;
+};
+
+void MobileVRInterface::uninitialize() {
+ if (initialized) {
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ if (arvr_server != NULL) {
+ // no longer our primary interface
+ arvr_server->clear_primary_interface_if(this);
+ }
+
+ initialized = false;
+ };
+};
+
+Size2 MobileVRInterface::get_recommended_render_targetsize() {
+ _THREAD_SAFE_METHOD_
+
+ // we use half our window size
+ Size2 target_size = OS::get_singleton()->get_window_size();
+ target_size.x *= 0.5 * oversample;
+ target_size.y *= oversample;
+
+ return target_size;
+};
+
+Transform MobileVRInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
+ _THREAD_SAFE_METHOD_
+
+ Transform transform_for_eye;
+
+ ARVRServer *arvr_server = ARVRServer::get_singleton();
+ ERR_FAIL_NULL_V(arvr_server, transform_for_eye);
+
+ if (initialized) {
+ float world_scale = arvr_server->get_world_scale();
+
+ // we don't need to check for the existance of our HMD, doesn't effect our values...
+ // note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction...
+ if (p_eye == ARVRInterface::EYE_LEFT) {
+ transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale);
+ } else if (p_eye == ARVRInterface::EYE_RIGHT) {
+ transform_for_eye.origin.x = intraocular_dist * 0.01 * 0.5 * world_scale;
+ } else {
+ // for mono we don't reposition, we want our center position.
+ };
+
+ // just scale our origin point of our transform
+ Transform hmd_transform;
+ hmd_transform.basis = orientation;
+ hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0);
+
+ transform_for_eye = p_cam_transform * (arvr_server->get_reference_frame()) * hmd_transform * transform_for_eye;
+ } else {
+ // huh? well just return what we got....
+ transform_for_eye = p_cam_transform;
+ };
+
+ return transform_for_eye;
+};
+
+CameraMatrix MobileVRInterface::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+ _THREAD_SAFE_METHOD_
+
+ CameraMatrix eye;
+
+ if (p_eye == ARVRInterface::EYE_MONO) {
+ ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real cameras properties
+ // which probably means implementing a specific class for iOS and Android. For now this is purely here as an example.
+ // Note also that if you use a normal viewport with AR/VR turned off you can still use the tracker output of this interface
+ // to position a stock standard Godot camera and have control over this.
+ // This will make more sense when we implement ARkit on iOS (probably a separate interface).
+ eye.set_perspective(60.0, p_aspect, p_z_near, p_z_far, false);
+ } else {
+ eye.set_for_hmd(p_eye == ARVRInterface::EYE_LEFT ? 1 : 2, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far);
+ };
+
+ return eye;
+};
+
+void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
+ _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());
+
+ float offset_x = 0.0;
+ float aspect_ratio = 0.5 * p_screen_rect.size.x / p_screen_rect.size.y;
+ Vector2 eye_center;
+
+ if (p_eye == ARVRInterface::EYE_LEFT) {
+ offset_x = -1.0;
+ eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0);
+ } else if (p_eye == ARVRInterface::EYE_RIGHT) {
+ eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0);
+ }
+
+ // unset our render target so we are outputting to our main screen by making RasterizerStorageGLES3::system_fbo our current FBO
+ VSG::rasterizer->set_current_render_target(RID());
+
+ // now output to screen
+ // VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0);
+
+ // get our render target
+ RID eye_texture = VSG::storage->render_target_get_texture(p_render_target);
+ uint32_t texid = VS::get_singleton()->texture_get_texid(eye_texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texid);
+
+ lens_shader.bind();
+ lens_shader.set_uniform(LensDistortedShaderGLES3::OFFSET_X, offset_x);
+ lens_shader.set_uniform(LensDistortedShaderGLES3::K1, k1);
+ lens_shader.set_uniform(LensDistortedShaderGLES3::K2, k2);
+ lens_shader.set_uniform(LensDistortedShaderGLES3::EYE_CENTER, eye_center);
+ lens_shader.set_uniform(LensDistortedShaderGLES3::UPSCALE, oversample);
+ lens_shader.set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio);
+
+ glBindVertexArray(half_screen_array);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glBindVertexArray(0);
+};
+
+void MobileVRInterface::process() {
+ _THREAD_SAFE_METHOD_
+
+ if (initialized) {
+ set_position_from_sensors();
+ };
+};
+
+MobileVRInterface::MobileVRInterface() {
+ initialized = false;
+
+ // Just set some defaults for these. At some point we need to look at adding a lookup table for common device + headset combos and/or support reading cardboard QR codes
+ eye_height = 1.85;
+ intraocular_dist = 6.0;
+ display_width = 14.5;
+ display_to_lens = 4.0;
+ oversample = 1.5;
+ k1 = 0.215;
+ k2 = 0.215;
+ last_ticks = 0;
+
+ // create our shader stuff
+ lens_shader.init();
+
+ {
+ glGenBuffers(1, &half_screen_quad);
+ glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad);
+ {
+ const float qv[16] = {
+ 0, -1,
+ -1, -1,
+ 0, 1,
+ -1, 1,
+ 1, 1,
+ 1, 1,
+ 1, -1,
+ 1, -1,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+
+ glGenVertexArrays(1, &half_screen_array);
+ glBindVertexArray(half_screen_array);
+ glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad);
+ glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, ((uint8_t *)NULL) + 8);
+ glEnableVertexAttribArray(4);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ }
+};
+
+MobileVRInterface::~MobileVRInterface() {
+ // and make sure we cleanup if we haven't already
+ if (is_initialized()) {
+ uninitialize();
+ };
+};
diff --git a/modules/mobile_vr/mobile_interface.h b/modules/mobile_vr/mobile_interface.h
new file mode 100644
index 0000000000..747377ae46
--- /dev/null
+++ b/modules/mobile_vr/mobile_interface.h
@@ -0,0 +1,152 @@
+/*************************************************************************/
+/* mobile_interface.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef MOBILE_VR_INTERFACE_H
+#define MOBILE_VR_INTERFACE_H
+
+#include "servers/arvr/arvr_interface.h"
+#include "servers/arvr/arvr_positional_tracker.h"
+
+#include "shaders/lens_distorted.glsl.gen.h"
+
+/**
+ @author Bastiaan Olij <mux213@gmail.com>
+
+ The mobile interface is a native VR interface that can be used on Android and iOS phones.
+ It contains a basic implementation supporting 3DOF tracking if a gyroscope and accelerometer are
+ present and sets up the proper projection matrices based on the values provided.
+
+ We're planning to eventually do separate interfaces towards mobile SDKs that have far more capabilities and
+ do not rely on the user providing most of these settings (though enhancing this with auto detection features
+ based on the device we're running on would be cool). I'm mostly adding this as an example or base plate for
+ more advanced interfaces.
+*/
+
+class MobileVRInterface : public ARVRInterface {
+ GDCLASS(MobileVRInterface, ARVRInterface);
+
+private:
+ bool initialized;
+ Basis orientation;
+ float eye_height;
+ uint64_t last_ticks;
+
+ LensDistortedShaderGLES3 lens_shader;
+ GLuint half_screen_quad;
+ GLuint half_screen_array;
+
+ real_t intraocular_dist;
+ real_t display_width;
+ real_t display_to_lens;
+ real_t oversample;
+
+ //@TODO not yet used, these are needed in our distortion shader...
+ real_t k1;
+ real_t k2;
+
+ /*
+ logic for processing our sensor data, this was originally in our positional tracker logic but I think
+ that doesn't make sense in hindsight. It only makes marginally more sense to park it here for now,
+ this probably deserves an object of its own
+ */
+ Vector3 scale_magneto(const Vector3 &p_magnetometer);
+ Basis combine_acc_mag(const Vector3 &p_grav, const Vector3 &p_magneto);
+
+ int mag_count;
+ bool has_gyro;
+ bool sensor_first;
+ Vector3 last_accerometer_data;
+ Vector3 last_magnetometer_data;
+ Vector3 mag_current_min;
+ Vector3 mag_current_max;
+ Vector3 mag_next_min;
+ Vector3 mag_next_max;
+
+ ///@TODO a few support functions for trackers, most are math related and should likely be moved elsewhere
+ float floor_decimals(float p_value, float p_decimals) {
+ float power_of_10 = pow(10.0f, p_decimals);
+ return floor(p_value * power_of_10) / power_of_10;
+ };
+
+ Vector3 floor_decimals(const Vector3 &p_vector, float p_decimals) {
+ return Vector3(floor_decimals(p_vector.x, p_decimals), floor_decimals(p_vector.y, p_decimals), floor_decimals(p_vector.z, p_decimals));
+ };
+
+ Vector3 low_pass(const Vector3 &p_vector, const Vector3 &p_last_vector, float p_factor) {
+ return p_vector + (p_factor * (p_last_vector - p_vector));
+ };
+
+ Vector3 scrub(const Vector3 &p_vector, const Vector3 &p_last_vector, float p_decimals, float p_factor) {
+ return low_pass(floor_decimals(p_vector, p_decimals), p_last_vector, p_factor);
+ };
+
+ void set_position_from_sensors();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_iod(const real_t p_iod);
+ real_t get_iod() const;
+
+ void set_display_width(const real_t p_display_width);
+ real_t get_display_width() const;
+
+ void set_display_to_lens(const real_t p_display_to_lens);
+ real_t get_display_to_lens() const;
+
+ void set_oversample(const real_t p_oversample);
+ real_t get_oversample() const;
+
+ void set_k1(const real_t p_k1);
+ real_t get_k1() const;
+
+ void set_k2(const real_t p_k2);
+ real_t get_k2() const;
+
+ virtual StringName get_name() const;
+ virtual int get_capabilities() const;
+
+ virtual bool is_initialized();
+ virtual bool initialize();
+ virtual void uninitialize();
+
+ virtual Size2 get_recommended_render_targetsize();
+ virtual bool is_stereo();
+ virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
+ virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
+ virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect);
+
+ virtual void process();
+
+ MobileVRInterface();
+ ~MobileVRInterface();
+};
+
+#endif // MOBILE_VR_INTERFACE_H
diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp
new file mode 100644
index 0000000000..f742ecbf00
--- /dev/null
+++ b/modules/mobile_vr/register_types.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "mobile_interface.h"
+
+void register_mobile_vr_types() {
+ ClassDB::register_class<MobileVRInterface>();
+
+ Ref<MobileVRInterface> mobile_vr;
+ mobile_vr.instance();
+ ARVRServer::get_singleton()->add_interface(mobile_vr);
+}
+
+void unregister_mobile_vr_types() {
+}
diff --git a/modules/mobile_vr/register_types.h b/modules/mobile_vr/register_types.h
new file mode 100644
index 0000000000..a492fff397
--- /dev/null
+++ b/modules/mobile_vr/register_types.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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_mobile_vr_types();
+void unregister_mobile_vr_types();
diff --git a/modules/mobile_vr/shaders/SCsub b/modules/mobile_vr/shaders/SCsub
new file mode 100644
index 0000000000..cf53c9ebe0
--- /dev/null
+++ b/modules/mobile_vr/shaders/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import('env')
+
+if 'GLES3_GLSL' in env['BUILDERS']:
+ env.GLES3_GLSL('lens_distorted.glsl');
+
diff --git a/modules/mobile_vr/shaders/lens_distorted.glsl b/modules/mobile_vr/shaders/lens_distorted.glsl
new file mode 100644
index 0000000000..5a2975d737
--- /dev/null
+++ b/modules/mobile_vr/shaders/lens_distorted.glsl
@@ -0,0 +1,59 @@
+[vertex]
+
+layout(location=0) in highp vec4 vertex_attrib;
+layout(location=4) in vec2 uv_in;
+
+uniform float offset_x;
+
+out vec2 uv_interp;
+
+void main() {
+
+ uv_interp = uv_in;
+ gl_Position = vec4(vertex_attrib.x + offset_x, vertex_attrib.y, 0.0, 1.0);
+}
+
+[fragment]
+
+uniform sampler2D source; //texunit:0
+
+uniform vec2 eye_center;
+uniform float k1;
+uniform float k2;
+uniform float upscale;
+uniform float aspect_ratio;
+
+in vec2 uv_interp;
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+ vec2 coords = uv_interp;
+ vec2 offset = coords - eye_center;
+
+ // take aspect ratio into account
+ offset.y /= aspect_ratio;
+
+ // distort
+ vec2 offset_sq = offset * offset;
+ float radius_sq = offset_sq.x + offset_sq.y;
+ float radius_s4 = radius_sq * radius_sq;
+ float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4);
+ offset *= distortion_scale;
+
+ // reapply aspect ratio
+ offset.y *= aspect_ratio;
+
+ // add our eye center back in
+ coords = offset + eye_center;
+ coords /= upscale;
+
+ // and check our color
+ if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) {
+ frag_color = vec4(0.0, 0.0, 0.0, 1.0);
+ } else {
+ coords = (coords + vec2(1.0)) / vec2(2.0);
+ frag_color = textureLod(source, coords, 0.0);
+ }
+}
+
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
new file mode 100644
index 0000000000..18a20ecac4
--- /dev/null
+++ b/modules/mono/SCsub
@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+
+Import('env')
+
+from compat import byte_to_str
+
+def make_cs_files_header(src, dst):
+ with open(dst, 'w') as header:
+ header.write('/* This is an automatically generated file; DO NOT EDIT! OK THX */\n')
+ header.write('#ifndef _CS_FILES_DATA_H\n')
+ header.write('#define _CS_FILES_DATA_H\n\n')
+ header.write('#include "map.h"\n')
+ header.write('#include "ustring.h"\n')
+ inserted_files = ''
+ import os
+ for file in os.listdir(src):
+ if file.endswith('.cs'):
+ with open(os.path.join(src, file), 'rb') as f:
+ buf = f.read()
+ decomp_size = len(buf)
+ import zlib
+ buf = zlib.compress(buf)
+ name = os.path.splitext(file)[0]
+ header.write('\nstatic const int _cs_' + name + '_compressed_size = ' + str(len(buf)) + ';\n')
+ header.write('static const int _cs_' + name + '_uncompressed_size = ' + str(decomp_size) + ';\n')
+ header.write('static const unsigned char _cs_' + name + '_compressed[] = { ')
+ for i, buf_idx in enumerate(range(len(buf))):
+ if i > 0:
+ header.write(', ')
+ header.write(byte_to_str(buf[buf_idx]))
+ inserted_files += '\tr_files.insert(\"' + file + '\", ' \
+ 'CompressedFile(_cs_' + name + '_compressed_size, ' \
+ '_cs_' + name + '_uncompressed_size, ' \
+ '_cs_' + name + '_compressed));\n'
+ header.write(' };\n')
+ header.write('\nstruct CompressedFile\n' '{\n'
+ '\tint compressed_size;\n' '\tint uncompressed_size;\n' '\tconst unsigned char* data;\n'
+ '\n\tCompressedFile(int p_comp_size, int p_uncomp_size, const unsigned char* p_data)\n'
+ '\t{\n' '\t\tcompressed_size = p_comp_size;\n' '\t\tuncompressed_size = p_uncomp_size;\n'
+ '\t\tdata = p_data;\n' '\t}\n' '\n\tCompressedFile() {}\n' '};\n'
+ '\nvoid get_compressed_files(Map<String, CompressedFile>& r_files)\n' '{\n' + inserted_files + '}\n'
+ )
+ header.write('#endif // _CS_FILES_DATA_H')
+
+
+env.add_source_files(env.modules_sources, '*.cpp')
+env.add_source_files(env.modules_sources, 'mono_gd/*.cpp')
+env.add_source_files(env.modules_sources, 'utils/*.cpp')
+
+if env['tools']:
+ env.add_source_files(env.modules_sources, 'editor/*.cpp')
+ make_cs_files_header('glue/cs_files', 'glue/cs_compressed.gen.h')
+
+vars = Variables()
+vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
+vars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
+vars.Update(env)
+
+# Glue sources
+if env['mono_glue']:
+ env.add_source_files(env.modules_sources, 'glue/*.cpp')
+else:
+ env.Append(CPPDEFINES=['MONO_GLUE_DISABLED'])
+
+if ARGUMENTS.get('yolo_copy', False):
+ env.Append(CPPDEFINES=['YOLO_COPY'])
+
+
+# Build GodotSharpTools solution
+
+
+import os
+
+
+def find_msbuild_unix(filename):
+ import os.path
+ import sys
+
+ hint_dirs = ['/opt/novell/mono/bin']
+ if sys.platform == "darwin":
+ hint_dirs = ['/Library/Frameworks/Mono.framework/Versions/Current/bin'] + hint_dirs
+
+ for hint_dir in hint_dirs:
+ hint_path = os.path.join(hint_dir, filename)
+ if os.path.isfile(hint_path):
+ return hint_path
+ elif os.path.isfile(hint_path + ".exe"):
+ return hint_path + ".exe"
+
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, filename)
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
+ return hint_path + ".exe"
+
+ return None
+
+
+def find_msbuild_windows():
+ import mono_reg_utils as monoreg
+
+ bits = env['bits']
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+ else:
+ mono_root = monoreg.find_mono_root_dir(bits)
+
+ if not mono_root:
+ raise RuntimeError('Cannot find mono root directory')
+
+ msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
+
+ if msbuild_tools_path:
+ return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), os.path.join(mono_root, 'lib', 'mono', '4.5'))
+ else:
+ msbuild_mono = os.path.join(mono_root, 'bin', 'msbuild.bat')
+
+ if os.path.isfile(msbuild_mono):
+ return (msbuild_mono, '')
+
+ return None
+
+
+def mono_build_solution(source, target, env):
+ import subprocess
+ import mono_reg_utils as monoreg
+ from shutil import copyfile
+
+ framework_path_override = ''
+
+ if os.name == 'nt':
+ msbuild_info = find_msbuild_windows()
+ if msbuild_info is None:
+ raise RuntimeError('Cannot find MSBuild executable')
+ msbuild_path = msbuild_info[0]
+ framework_path_override = msbuild_info[1]
+ else:
+ msbuild_path = find_msbuild_unix('msbuild')
+ if msbuild_path is None:
+ xbuild_fallback = env['xbuild_fallback']
+
+ if xbuild_fallback and os.name == 'nt':
+ print("Option 'xbuild_fallback' not supported on Windows")
+ xbuild_fallback = False
+
+ if xbuild_fallback:
+ print('Cannot find MSBuild executable, trying with xbuild')
+ print('Warning: xbuild is deprecated')
+
+ msbuild_path = find_msbuild_unix('xbuild')
+
+ if msbuild_path is None:
+ raise RuntimeError('Cannot find xbuild executable')
+ else:
+ raise RuntimeError('Cannot find MSBuild executable')
+
+ print('MSBuild path: ' + msbuild_path)
+
+ build_config = 'Release'
+
+ msbuild_args = [
+ msbuild_path,
+ os.path.abspath(str(source[0])),
+ '/p:Configuration=' + build_config,
+ ]
+
+ if framework_path_override:
+ msbuild_args += ['/p:FrameworkPathOverride=' + framework_path_override]
+
+ msbuild_env = os.environ.copy()
+
+ # Needed when running from Developer Command Prompt for VS
+ if 'PLATFORM' in msbuild_env:
+ del msbuild_env['PLATFORM']
+
+ try:
+ subprocess.check_call(msbuild_args, env=msbuild_env)
+ except subprocess.CalledProcessError:
+ raise RuntimeError('GodotSharpTools build failed')
+
+ src_dir = os.path.abspath(os.path.join(str(source[0]), os.pardir, 'bin', build_config))
+ dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))
+
+ if not os.path.isdir(dst_dir):
+ if os.path.exists(dst_dir):
+ raise RuntimeError('Target directory is a file')
+ os.makedirs(dst_dir)
+
+ asm_file = 'GodotSharpTools.dll'
+
+ copyfile(os.path.join(src_dir, asm_file), os.path.join(dst_dir, asm_file))
+
+
+mono_sln_builder = Builder(action = mono_build_solution)
+env.Append(BUILDERS={'MonoBuildSolution': mono_sln_builder})
+env.MonoBuildSolution(
+ os.path.join(Dir('#bin').abspath, 'GodotSharpTools.dll'),
+ 'editor/GodotSharpTools/GodotSharpTools.sln'
+)
diff --git a/modules/mono/config.py b/modules/mono/config.py
new file mode 100644
index 0000000000..7ad135e0b9
--- /dev/null
+++ b/modules/mono/config.py
@@ -0,0 +1,184 @@
+
+import imp
+import os
+import sys
+
+from SCons.Script import BoolVariable, Environment, Variables
+
+
+monoreg = imp.load_source('mono_reg_utils', 'modules/mono/mono_reg_utils.py')
+
+
+def find_file_in_dir(directory, files, prefix='', extension=''):
+ if not extension.startswith('.'):
+ extension = '.' + extension
+ for curfile in files:
+ if os.path.isfile(os.path.join(directory, prefix + curfile + extension)):
+ return curfile
+ return ''
+
+
+def can_build(platform):
+ if platform in ["javascript"]:
+ return False # Not yet supported
+ return True
+
+
+def is_enabled():
+ # The module is disabled by default. Use module_mono_enabled=yes to enable it.
+ return False
+
+
+def copy_file_no_replace(src_dir, dst_dir, name):
+ from shutil import copyfile
+
+ src_path = os.path.join(src_dir, name)
+ dst_path = os.path.join(dst_dir, name)
+ need_copy = True
+
+ if not os.path.isdir(dst_dir):
+ os.mkdir(dst_dir)
+ elif os.path.exists(dst_path):
+ need_copy = False
+
+ if need_copy:
+ copyfile(src_path, dst_path)
+
+
+def configure(env):
+ env.use_ptrcall = True
+ env.add_module_version_string("mono")
+
+ envvars = Variables()
+ envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
+ envvars.Update(env)
+
+ bits = env['bits']
+
+ mono_static = env['mono_static']
+
+ mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
+
+ if env['platform'] == 'windows':
+ if mono_static:
+ raise RuntimeError('mono-static: Not supported on Windows')
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ elif os.name == 'nt':
+ mono_root = monoreg.find_mono_root_dir(bits)
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+ elif os.name == 'nt':
+ mono_root = monoreg.find_mono_root_dir(bits)
+
+ if not mono_root:
+ raise RuntimeError('Mono installation directory not found')
+
+ mono_lib_path = os.path.join(mono_root, 'lib')
+
+ env.Append(LIBPATH=mono_lib_path)
+ env.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
+
+ mono_lib_name = find_file_in_dir(mono_lib_path, mono_lib_names, extension='.lib')
+
+ if not mono_lib_name:
+ raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
+
+ if os.getenv('VCINSTALLDIR'):
+ env.Append(LINKFLAGS=mono_lib_name + Environment()['LIBSUFFIX'])
+ else:
+ env.Append(LIBS=mono_lib_name)
+
+ mono_bin_path = os.path.join(mono_root, 'bin')
+
+ mono_dll_name = find_file_in_dir(mono_bin_path, mono_lib_names, extension='.dll')
+
+ if not mono_dll_name:
+ raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
+
+ copy_file_no_replace(mono_bin_path, 'bin', mono_dll_name + '.dll')
+ else:
+ sharedlib_ext = '.dylib' if sys.platform == 'darwin' else '.so'
+
+ mono_root = ''
+
+ if bits == '32':
+ if os.getenv('MONO32_PREFIX'):
+ mono_root = os.getenv('MONO32_PREFIX')
+ else:
+ if os.getenv('MONO64_PREFIX'):
+ mono_root = os.getenv('MONO64_PREFIX')
+
+ if mono_root:
+ mono_lib_path = os.path.join(mono_root, 'lib')
+
+ env.Append(LIBPATH=mono_lib_path)
+ env.Append(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0'))
+
+ mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a')
+
+ if not mono_lib:
+ raise RuntimeError('Could not find mono library in: ' + mono_lib_path)
+
+ env.Append(CPPFLAGS=['-D_REENTRANT'])
+
+ if mono_static:
+ mono_lib_file = os.path.join(mono_lib_path, 'lib' + mono_lib + '.a')
+
+ if sys.platform == "darwin":
+ env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file])
+ elif sys.platform == "linux" or sys.platform == "linux2":
+ env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive'])
+ else:
+ raise RuntimeError('mono-static: Not supported on this platform')
+ else:
+ env.Append(LIBS=[mono_lib])
+
+ if sys.platform == "darwin":
+ env.Append(LIBS=['iconv', 'pthread'])
+ elif sys.platform == "linux" or sys.platform == "linux2":
+ env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
+
+ if not mono_static:
+ mono_so_name = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+
+ if not mono_so_name:
+ raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
+
+ copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
+ else:
+ if mono_static:
+ raise RuntimeError('mono-static: Not supported with pkg-config. Specify a mono prefix manually')
+
+ env.ParseConfig('pkg-config monosgen-2 --cflags --libs')
+
+ mono_lib_path = ''
+ mono_so_name = ''
+
+ tmpenv = Environment()
+ tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
+
+ for hint_dir in tmpenv['LIBPATH']:
+ name_found = find_file_in_dir(hint_dir, mono_lib_names, prefix='lib', extension=sharedlib_ext)
+ if name_found:
+ mono_lib_path = hint_dir
+ mono_so_name = name_found
+ break
+
+ if not mono_so_name:
+ raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
+
+ copy_file_no_replace(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
+
+ env.Append(LINKFLAGS='-rdynamic')
+
+
+def get_doc_classes():
+ return ["@C#", "CSharpScript", "GodotSharp"]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
new file mode 100644
index 0000000000..161e130a07
--- /dev/null
+++ b/modules/mono/csharp_script.cpp
@@ -0,0 +1,2061 @@
+/*************************************************************************/
+/* csharp_script.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "csharp_script.h"
+
+#include <mono/metadata/threads.h>
+
+#include "os/file_access.h"
+#include "os/os.h"
+#include "os/thread.h"
+#include "project_settings.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/bindings_generator.h"
+#include "editor/csharp_project.h"
+#include "editor/editor_node.h"
+#include "editor/godotsharp_editor.h"
+#include "utils/string_utils.h"
+#endif
+
+#include "godotsharp_dirs.h"
+#include "mono_gd/gd_mono_class.h"
+#include "mono_gd/gd_mono_marshal.h"
+#include "signal_awaiter_utils.h"
+
+#define CACHED_STRING_NAME(m_var) (CSharpLanguage::get_singleton()->get_string_names().m_var)
+
+#ifdef TOOLS_ENABLED
+static bool _create_project_solution_if_needed() {
+
+ String sln_path = GodotSharpDirs::get_project_sln_path();
+ String csproj_path = GodotSharpDirs::get_project_csproj_path();
+
+ if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
+ // A solution does not yet exist, create a new one
+
+ CRASH_COND(GodotSharpEditor::get_singleton() == NULL);
+ return GodotSharpEditor::get_singleton()->call("_create_project_solution");
+ }
+
+ return true;
+}
+#endif
+
+CSharpLanguage *CSharpLanguage::singleton = NULL;
+
+String CSharpLanguage::get_name() const {
+
+ return "C#";
+}
+
+String CSharpLanguage::get_type() const {
+
+ return "CSharpScript";
+}
+
+String CSharpLanguage::get_extension() const {
+
+ return "cs";
+}
+
+Error CSharpLanguage::execute_file(const String &p_path) {
+
+ // ??
+ return OK;
+}
+
+#ifdef TOOLS_ENABLED
+void gdsharp_editor_init_callback() {
+
+ EditorNode *editor = EditorNode::get_singleton();
+ editor->add_child(memnew(GodotSharpEditor(editor)));
+}
+#endif
+
+void CSharpLanguage::init() {
+
+ gdmono = memnew(GDMono);
+ gdmono->initialize();
+
+#ifdef MONO_GLUE_DISABLED
+ WARN_PRINT("This binary is built with `mono_glue=no` and cannot be used for scripting");
+#endif
+
+#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
+ if (gdmono->get_editor_tools_assembly() != NULL) {
+ List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
+ BindingsGenerator::handle_cmdline_args(cmdline_args);
+ }
+#endif
+
+#ifdef TOOLS_ENABLED
+ EditorNode::add_init_callback(&gdsharp_editor_init_callback);
+#endif
+}
+
+void CSharpLanguage::finish() {
+
+ // Release gchandle bindings before finalizing mono runtime
+ gchandle_bindings.clear();
+
+ if (gdmono) {
+ memdelete(gdmono);
+ gdmono = NULL;
+ }
+}
+
+void CSharpLanguage::get_reserved_words(List<String> *p_words) const {
+
+ static const char *_reserved_words[] = {
+ // Reserved keywords
+ "abstract",
+ "as",
+ "base",
+ "bool",
+ "break",
+ "byte",
+ "case",
+ "catch",
+ "char",
+ "checked",
+ "class",
+ "const",
+ "continue",
+ "decimal",
+ "default",
+ "delegate",
+ "do",
+ "double",
+ "else",
+ "enum",
+ "event",
+ "explicit",
+ "extern",
+ "false",
+ "finally",
+ "fixed",
+ "float",
+ "for",
+ "forech",
+ "goto",
+ "if",
+ "implicit",
+ "in",
+ "int",
+ "interface",
+ "internal",
+ "is",
+ "lock",
+ "long",
+ "namespace",
+ "new",
+ "null",
+ "object",
+ "operator",
+ "out",
+ "override",
+ "params",
+ "private",
+ "protected",
+ "public",
+ "readonly",
+ "ref",
+ "return",
+ "sbyte",
+ "sealed",
+ "short",
+ "sizeof",
+ "stackalloc",
+ "static",
+ "string",
+ "struct",
+ "switch",
+ "this",
+ "throw",
+ "true",
+ "try",
+ "typeof",
+ "uint",
+ "ulong",
+ "unchecked",
+ "unsafe",
+ "ushort",
+ "using",
+ "virtual",
+ "volatile",
+ "void",
+ "while",
+
+ // Contextual keywords. Not reserved words, but I guess we should include
+ // them because this seems to be used only for syntax highlighting.
+ "add",
+ "ascending",
+ "by",
+ "descending",
+ "dynamic",
+ "equals",
+ "from",
+ "get",
+ "global",
+ "group",
+ "in",
+ "into",
+ "join",
+ "let",
+ "on",
+ "orderby",
+ "partial",
+ "remove",
+ "select",
+ "set",
+ "value",
+ "var",
+ "where",
+ "yield",
+ 0
+ };
+
+ const char **w = _reserved_words;
+
+ while (*w) {
+ p_words->push_back(*w);
+ w++;
+ }
+}
+
+void CSharpLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
+
+ p_delimiters->push_back("//"); // single-line comment
+ p_delimiters->push_back("/* */"); // delimited comment
+}
+
+void CSharpLanguage::get_string_delimiters(List<String> *p_delimiters) const {
+
+ p_delimiters->push_back("' '"); // character literal
+ p_delimiters->push_back("\" \""); // regular string literal
+ p_delimiters->push_back("@\" \""); // verbatim string literal
+}
+
+Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
+
+ String script_template = "using " BINDINGS_NAMESPACE ";\n"
+ "using System;\n"
+ "\n"
+ "public class %CLASS_NAME% : %BASE_CLASS_NAME%\n"
+ "{\n"
+ " // Member variables here, example:\n"
+ " // private int a = 2;\n"
+ " // private string b = \"textvar\";\n"
+ "\n"
+ " public override void _Ready()\n"
+ " {\n"
+ " // Called every time the node is added to the scene.\n"
+ " // Initialization here\n"
+ " \n"
+ " }\n"
+ "\n"
+ "// public override void _Process(float delta)\n"
+ "// {\n"
+ "// // Called every frame. Delta is time since last frame.\n"
+ "// // Update game logic here.\n"
+ "// \n"
+ "// }\n"
+ "}\n";
+
+ script_template = script_template.replace("%BASE_CLASS_NAME%", p_base_class_name)
+ .replace("%CLASS_NAME%", p_class_name);
+
+ Ref<CSharpScript> script;
+ script.instance();
+ script->set_source_code(script_template);
+ script->set_name(p_class_name);
+
+ return script;
+}
+
+bool CSharpLanguage::is_using_templates() {
+
+ return true;
+}
+
+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();
+ src = src.replace("%BASE%", p_base_class_name)
+ .replace("%CLASS%", p_class_name)
+ .replace("%TS%", _get_indentation());
+ p_script->set_source_code(src);
+}
+
+Script *CSharpLanguage::create_script() const {
+
+ return memnew(CSharpScript);
+}
+
+bool CSharpLanguage::has_named_classes() const {
+
+ return false;
+}
+
+bool CSharpLanguage::supports_builtin_mode() const {
+
+ return false;
+}
+
+static String variant_type_to_managed_name(const String &p_var_type_name) {
+
+ if (p_var_type_name.empty())
+ return "object";
+
+ if (!ClassDB::class_exists(p_var_type_name)) {
+ Variant::Type var_types[] = {
+ Variant::BOOL,
+ Variant::INT,
+ Variant::REAL,
+ Variant::STRING,
+ Variant::VECTOR2,
+ Variant::RECT2,
+ Variant::VECTOR3,
+ Variant::TRANSFORM2D,
+ Variant::PLANE,
+ Variant::QUAT,
+ Variant::RECT3,
+ Variant::BASIS,
+ Variant::TRANSFORM,
+ Variant::COLOR,
+ Variant::NODE_PATH,
+ Variant::_RID
+ };
+
+ for (int i = 0; i < sizeof(var_types) / sizeof(Variant::Type); i++) {
+ if (p_var_type_name == Variant::get_type_name(var_types[i]))
+ return p_var_type_name;
+ }
+
+ if (p_var_type_name == "String")
+ return "string"; // I prefer this one >:[
+
+ // TODO these will be rewritten later into custom containers
+
+ if (p_var_type_name == "Array")
+ return "object[]";
+
+ if (p_var_type_name == "Dictionary")
+ return "Dictionary<object, object>";
+
+ if (p_var_type_name == "PoolByteArray")
+ return "byte[]";
+ if (p_var_type_name == "PoolIntArray")
+ return "int[]";
+ if (p_var_type_name == "PoolRealArray")
+ return "float[]";
+ if (p_var_type_name == "PoolStringArray")
+ return "string[]";
+ if (p_var_type_name == "PoolVector2Array")
+ return "Vector2[]";
+ if (p_var_type_name == "PoolVector3Array")
+ return "Vector3[]";
+ if (p_var_type_name == "PoolColorArray")
+ return "Color[]";
+
+ return "object";
+ }
+
+ return p_var_type_name;
+}
+
+String CSharpLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const {
+#ifdef TOOLS_ENABLED
+ // FIXME
+ // - Due to Godot's API limitation this just appends the function to the end of the file
+ // - Use fully qualified name if there is ambiguity
+ String s = "private void " + p_name + "(";
+ for (int i = 0; i < p_args.size(); i++) {
+ const String &arg = p_args[i];
+
+ if (i > 0)
+ s += ", ";
+
+ s += variant_type_to_managed_name(arg.get_slice(":", 1)) + " " + escape_csharp_keyword(arg.get_slice(":", 0));
+ }
+ s += ")\n{\n // Replace with function body\n}\n";
+
+ return s;
+#else
+ return String();
+#endif
+}
+
+String CSharpLanguage::_get_indentation() const {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0);
+
+ if (use_space_indentation) {
+ int indent_size = EDITOR_DEF("text_editor/indent/size", 4);
+
+ String space_indent = "";
+ for (int i = 0; i < indent_size; i++) {
+ space_indent += " ";
+ }
+ return space_indent;
+ }
+ }
+#endif
+ return "\t";
+}
+
+void CSharpLanguage::frame() {
+
+ const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle;
+
+ if (task_scheduler_handle.is_valid()) {
+ MonoObject *task_scheduler = task_scheduler_handle->get_target();
+
+ if (task_scheduler) {
+ GDMonoUtils::GodotTaskScheduler_Activate thunk = CACHED_METHOD_THUNK(GodotTaskScheduler, Activate);
+
+ ERR_FAIL_NULL(thunk);
+
+ MonoObject *ex;
+ thunk(task_scheduler, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL();
+ }
+ }
+ }
+}
+
+struct CSharpScriptDepSort {
+
+ // must support sorting so inheritance works properly (parent must be reloaded first)
+ bool operator()(const Ref<CSharpScript> &A, const Ref<CSharpScript> &B) const {
+ if (A == B)
+ return false; // shouldn't happen but..
+ GDMonoClass *I = B->base;
+ while (I) {
+ if (I == A->script_class) {
+ // A is a base of B
+ return true;
+ }
+
+ I = I->get_parent_class();
+ }
+
+ return false; // not a base
+ }
+};
+
+void CSharpLanguage::reload_all_scripts() {
+
+#ifdef DEBUG_ENABLED
+
+#ifndef NO_THREADS
+ lock->lock();
+#endif
+
+ List<Ref<CSharpScript> > scripts;
+
+ SelfList<CSharpScript> *elem = script_list.first();
+ while (elem) {
+ if (elem->self()->get_path().is_resource_file()) {
+ scripts.push_back(Ref<CSharpScript>(elem->self())); //cast to gdscript to avoid being erased by accident
+ }
+ elem = elem->next();
+ }
+
+#ifndef NO_THREADS
+ lock->unlock();
+#endif
+
+ //as scripts are going to be reloaded, must proceed without locking here
+
+ scripts.sort_custom<CSharpScriptDepSort>(); //update in inheritance dependency order
+
+ for (List<Ref<CSharpScript> >::Element *E = scripts.front(); E; E = E->next()) {
+ E->get()->load_source_code(E->get()->get_path());
+ E->get()->reload(true);
+ }
+#endif
+}
+
+void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
+
+ (void)p_script; // UNUSED
+
+#ifdef TOOLS_ENABLED
+ MonoReloadNode::get_singleton()->restart_reload_timer();
+ reload_assemblies_if_needed(p_soft_reload);
+#endif
+}
+
+#ifdef TOOLS_ENABLED
+void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
+
+ if (gdmono->is_runtime_initialized()) {
+
+ GDMonoAssembly *proj_assembly = gdmono->get_project_assembly();
+
+ String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
+
+ if (proj_assembly) {
+ String proj_asm_path = proj_assembly->get_path();
+
+ if (!FileAccess::exists(proj_assembly->get_path())) {
+ // Maybe it wasn't loaded from the default path, so check this as well
+ proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name);
+ if (!FileAccess::exists(proj_asm_path))
+ return; // No assembly to load
+ }
+
+ if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time())
+ return; // Already up to date
+ } else {
+ if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name)))
+ return; // No assembly to load
+ }
+ }
+
+#ifndef NO_THREADS
+ lock->lock();
+#endif
+
+ List<Ref<CSharpScript> > scripts;
+
+ SelfList<CSharpScript> *elem = script_list.first();
+ while (elem) {
+ if (elem->self()->get_path().is_resource_file()) {
+
+ scripts.push_back(Ref<CSharpScript>(elem->self())); //cast to CSharpScript to avoid being erased by accident
+ }
+ elem = elem->next();
+ }
+
+#ifndef NO_THREADS
+ lock->unlock();
+#endif
+
+ //when someone asks you why dynamically typed languages are easier to write....
+
+ Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
+
+ //as scripts are going to be reloaded, must proceed without locking here
+
+ scripts.sort_custom<CSharpScriptDepSort>(); //update in inheritance dependency order
+
+ for (List<Ref<CSharpScript> >::Element *E = scripts.front(); E; E = E->next()) {
+
+ to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant> > >());
+
+ if (!p_soft_reload) {
+
+ //save state and remove script from instances
+ Map<ObjectID, List<Pair<StringName, Variant> > > &map = to_reload[E->get()];
+
+ while (E->get()->instances.front()) {
+ Object *obj = E->get()->instances.front()->get();
+ //save instance info
+ List<Pair<StringName, Variant> > state;
+ if (obj->get_script_instance()) {
+
+ obj->get_script_instance()->get_property_state(state);
+
+ Ref<MonoGCHandle> gchandle = CAST_CSHARP_INSTANCE(obj->get_script_instance())->gchandle;
+ if (gchandle.is_valid())
+ gchandle->release();
+
+ map[obj->get_instance_id()] = state;
+ obj->set_script(RefPtr());
+ }
+ }
+
+ //same thing for placeholders
+ while (E->get()->placeholders.size()) {
+
+ Object *obj = E->get()->placeholders.front()->get()->get_owner();
+ //save instance info
+ List<Pair<StringName, Variant> > state;
+ if (obj->get_script_instance()) {
+ obj->get_script_instance()->get_property_state(state);
+ map[obj->get_instance_id()] = state;
+ obj->set_script(RefPtr());
+ }
+ }
+
+ for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) {
+ map[F->key()] = F->get(); //pending to reload, use this one instead
+ }
+
+ E->get()->_clear();
+ }
+ }
+
+ if (gdmono->reload_scripts_domain() != OK)
+ return;
+
+ for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
+
+ Ref<CSharpScript> scr = E->key();
+ scr->exports_invalidated = true;
+ scr->reload(p_soft_reload);
+ scr->update_exports();
+
+ //restore state if saved
+ for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) {
+
+ Object *obj = ObjectDB::get_instance(F->key());
+ if (!obj)
+ continue;
+
+ if (!p_soft_reload) {
+ //clear it just in case (may be a pending reload state)
+ obj->set_script(RefPtr());
+ }
+ obj->set_script(scr.get_ref_ptr());
+ if (!obj->get_script_instance()) {
+ //failed, save reload state for next time if not saved
+ if (!scr->pending_reload_state.has(obj->get_instance_id())) {
+ scr->pending_reload_state[obj->get_instance_id()] = F->get();
+ }
+ continue;
+ }
+
+ for (List<Pair<StringName, Variant> >::Element *G = F->get().front(); G; G = G->next()) {
+ obj->get_script_instance()->set(G->get().first, G->get().second);
+ }
+
+ scr->pending_reload_state.erase(obj->get_instance_id()); //as it reloaded, remove pending state
+ }
+
+ //if instance states were saved, set them!
+ }
+
+ if (Engine::get_singleton()->is_editor_hint())
+ EditorNode::get_singleton()->get_property_editor()->update_tree();
+}
+#endif
+
+void CSharpLanguage::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("cs");
+}
+
+#ifdef TOOLS_ENABLED
+Error CSharpLanguage::open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) {
+
+ return GodotSharpEditor::get_singleton()->open_in_external_editor(p_script, p_line, p_col);
+}
+
+bool CSharpLanguage::overrides_external_editor() {
+
+ return GodotSharpEditor::get_singleton()->overrides_external_editor();
+}
+#endif
+
+void CSharpLanguage::thread_enter() {
+
+#if 0
+ if (mono->is_runtime_initialized()) {
+ GDMonoUtils::attach_current_thread();
+ }
+#endif
+}
+
+void CSharpLanguage::thread_exit() {
+
+#if 0
+ if (mono->is_runtime_initialized()) {
+ GDMonoUtils::detach_current_thread();
+ }
+#endif
+}
+
+bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
+
+ // Break because of parse error
+ if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) {
+ // TODO
+ //_debug_parse_err_line = p_line;
+ //_debug_parse_err_file = p_file;
+ //_debug_error = p_error;
+ ScriptDebugger::get_singleton()->debug(this, false);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
+
+ if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) {
+ // TODO
+ //_debug_parse_err_line = -1;
+ //_debug_parse_err_file = "";
+ //_debug_error = p_error;
+ ScriptDebugger::get_singleton()->debug(this, p_allow_continue);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void CSharpLanguage::set_language_index(int p_idx) {
+
+ ERR_FAIL_COND(lang_idx != -1);
+ lang_idx = p_idx;
+}
+
+CSharpLanguage::CSharpLanguage() {
+
+ ERR_FAIL_COND(singleton);
+ singleton = this;
+
+ gdmono = NULL;
+
+#ifdef NO_THREADS
+ lock = NULL;
+ gchandle_bind_lock = NULL;
+#else
+ lock = Mutex::create();
+ script_bind_lock = Mutex::create();
+#endif
+
+ lang_idx = -1;
+}
+
+CSharpLanguage::~CSharpLanguage() {
+
+ finish();
+
+ if (lock) {
+ memdelete(lock);
+ lock = NULL;
+ }
+
+ if (script_bind_lock) {
+ memdelete(script_bind_lock);
+ script_bind_lock = NULL;
+ }
+
+ singleton = NULL;
+}
+
+void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) {
+
+#ifdef DEBUG_ENABLED
+ // I don't trust you
+ if (p_object->get_script_instance())
+ CRASH_COND(NULL != CAST_CSHARP_INSTANCE(p_object->get_script_instance()));
+#endif
+
+ StringName type_name = p_object->get_class_name();
+
+ // ¯\_(ツ)_/¯
+ const ClassDB::ClassInfo *classinfo = ClassDB::classes.getptr(type_name);
+ while (classinfo && !classinfo->exposed)
+ classinfo = classinfo->inherits_ptr;
+ ERR_FAIL_NULL_V(classinfo, NULL);
+ type_name = classinfo->name;
+
+ GDMonoClass *type_class = GDMonoUtils::type_get_proxy_class(type_name);
+
+ ERR_FAIL_NULL_V(type_class, NULL);
+
+ MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(type_class, type_name, p_object);
+
+ ERR_FAIL_NULL_V(mono_object, NULL);
+
+ // Tie managed to unmanaged
+ bool strong_handle = true;
+ Reference *ref = Object::cast_to<Reference>(p_object);
+
+ if (ref) {
+ strong_handle = false;
+
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: _GodotSharp::_dispose_object(Object *p_object)
+
+ ref->reference();
+ }
+
+ Ref<MonoGCHandle> gchandle = strong_handle ? MonoGCHandle::create_strong(mono_object) :
+ MonoGCHandle::create_weak(mono_object);
+
+#ifndef NO_THREADS
+ script_bind_lock->lock();
+#endif
+
+ void *data = (void *)gchandle_bindings.insert(p_object, gchandle);
+
+#ifndef NO_THREADS
+ script_bind_lock->unlock();
+#endif
+
+ return data;
+}
+
+void CSharpLanguage::free_instance_binding_data(void *p_data) {
+
+ if (GDMono::get_singleton() == NULL) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!gchandle_bindings.empty());
+#endif
+ // Mono runtime finalized, all the gchandle bindings were already released
+ return;
+ }
+
+#ifndef NO_THREADS
+ script_bind_lock->lock();
+#endif
+
+ gchandle_bindings.erase((Map<Object *, Ref<MonoGCHandle> >::Element *)p_data);
+
+#ifndef NO_THREADS
+ script_bind_lock->unlock();
+#endif
+}
+
+void CSharpInstance::_ml_call_reversed(GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount) {
+
+ GDMonoClass *base = klass->get_parent_class();
+ if (base && base != script->native)
+ _ml_call_reversed(base, p_method, p_args, p_argcount);
+
+ GDMonoMethod *method = klass->get_method(p_method, p_argcount);
+
+ if (method) {
+ method->invoke(get_mono_object(), p_args);
+ }
+}
+
+CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle) {
+
+ CSharpInstance *instance = memnew(CSharpInstance);
+
+ Reference *ref = Object::cast_to<Reference>(p_owner);
+
+ instance->base_ref = ref != NULL;
+ instance->script = Ref<CSharpScript>(p_script);
+ instance->owner = p_owner;
+ instance->gchandle = p_gchandle;
+
+ if (instance->base_ref)
+ instance->_reference_owner_unsafe();
+
+ p_script->instances.insert(p_owner);
+
+ return instance;
+}
+
+MonoObject *CSharpInstance::get_mono_object() const {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(gchandle.is_null());
+#endif
+ return gchandle->get_target();
+}
+
+bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
+
+ ERR_FAIL_COND_V(!script.is_valid(), false);
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoField *field = script->script_class->get_field(p_name);
+
+ if (field) {
+ MonoObject *mono_object = get_mono_object();
+
+ ERR_EXPLAIN("Reference has been garbage collected?");
+ ERR_FAIL_NULL_V(mono_object, false);
+
+ field->set_value(mono_object, p_value);
+
+ return true;
+ }
+
+ top = top->get_parent_class();
+ }
+
+ // Call _set
+
+ Variant name = p_name;
+ const Variant *args[2] = { &name, &p_value };
+
+ MonoObject *mono_object = get_mono_object();
+ top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_set), 2);
+
+ if (method) {
+ MonoObject *ret = method->invoke(mono_object, args);
+
+ if (ret && GDMonoMarshal::unbox<MonoBoolean>(ret) == true)
+ return true;
+ }
+
+ top = top->get_parent_class();
+ }
+
+ return false;
+}
+
+bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
+
+ ERR_FAIL_COND_V(!script.is_valid(), false);
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoField *field = top->get_field(p_name);
+
+ if (field) {
+ MonoObject *mono_object = get_mono_object();
+
+ ERR_EXPLAIN("Reference has been garbage collected?");
+ ERR_FAIL_NULL_V(mono_object, false);
+
+ MonoObject *value = field->get_value(mono_object);
+ r_ret = GDMonoMarshal::mono_object_to_variant(value, field->get_type());
+ return true;
+ }
+
+ // Call _get
+
+ GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_get), 1);
+
+ if (method) {
+ Variant name = p_name;
+ const Variant *args[1] = { &name };
+
+ MonoObject *ret = method->invoke(get_mono_object(), args);
+
+ if (ret) {
+ r_ret = GDMonoMarshal::mono_object_to_variant(ret);
+ return true;
+ }
+ }
+
+ top = top->get_parent_class();
+ }
+
+ return false;
+}
+
+void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
+
+ for (Map<StringName, PropertyInfo>::Element *E = script->member_info.front(); E; E = E->next()) {
+ p_properties->push_back(E->value());
+ }
+}
+
+Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
+
+ if (script->member_info.has(p_name)) {
+ if (r_is_valid)
+ *r_is_valid = true;
+ return script->member_info[p_name].type;
+ }
+
+ if (r_is_valid)
+ *r_is_valid = false;
+
+ return Variant::NIL;
+}
+
+bool CSharpInstance::has_method(const StringName &p_method) const {
+
+ if (!script.is_valid())
+ return false;
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ if (top->has_method(p_method)) {
+ return true;
+ }
+
+ top = top->get_parent_class();
+ }
+
+ return false;
+}
+
+Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+
+ MonoObject *mono_object = get_mono_object();
+
+ ERR_EXPLAIN("Reference has been garbage collected?");
+ ERR_FAIL_NULL_V(mono_object, Variant());
+
+ if (!script.is_valid())
+ return Variant();
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoMethod *method = top->get_method(p_method, p_argcount);
+
+ if (method) {
+ MonoObject *return_value = method->invoke(mono_object, p_args);
+
+ if (return_value) {
+ return GDMonoMarshal::mono_object_to_variant(return_value, method->get_return_type());
+ } else {
+ return Variant();
+ }
+ }
+
+ top = top->get_parent_class();
+ }
+
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
+
+ return Variant();
+}
+
+void CSharpInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
+
+ if (script.is_valid()) {
+ MonoObject *mono_object = get_mono_object();
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoMethod *method = top->get_method(p_method, p_argcount);
+
+ if (method)
+ method->invoke(mono_object, p_args);
+
+ top = top->get_parent_class();
+ }
+ }
+}
+
+void CSharpInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
+
+ if (script.is_valid()) {
+ _ml_call_reversed(script->script_class, p_method, p_args, p_argcount);
+ }
+}
+
+void CSharpInstance::_reference_owner_unsafe() {
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!base_ref);
+#endif
+
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: _unreference_owner_unsafe()
+
+ // May not me referenced yet, so we must use init_ref() instead of reference()
+ Object::cast_to<Reference>(owner)->init_ref();
+}
+
+void CSharpInstance::_unreference_owner_unsafe() {
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!base_ref);
+#endif
+
+ // Called from CSharpInstance::mono_object_disposed() or ~CSharpInstance()
+
+ // Unsafe refcount decrement. The managed instance also counts as a reference.
+ // See: _reference_owner_unsafe()
+
+ if (Object::cast_to<Reference>(owner)->unreference()) {
+ memdelete(owner);
+ owner = NULL;
+ }
+}
+
+void CSharpInstance::mono_object_disposed() {
+
+ if (base_ref)
+ _unreference_owner_unsafe();
+}
+
+void CSharpInstance::refcount_incremented() {
+
+ CRASH_COND(!base_ref);
+
+ Reference *ref_owner = Object::cast_to<Reference>(owner);
+
+ if (ref_owner->reference_get_count() > 1) { // Remember the managed side holds a reference, hence 1 instead of 0 here
+ // The reference count was increased after the managed side was the only one referencing our owner.
+ // This means the owner is being referenced again by the unmanaged side,
+ // so the owner must hold the managed side alive again to avoid it from being GCed.
+
+ // Release the current weak handle and replace it with a strong handle.
+ uint32_t strong_gchandle = MonoGCHandle::make_strong_handle(gchandle->get_target());
+ gchandle->release();
+ gchandle->set_handle(strong_gchandle);
+ }
+}
+
+bool CSharpInstance::refcount_decremented() {
+
+ CRASH_COND(!base_ref);
+
+ Reference *ref_owner = Object::cast_to<Reference>(owner);
+
+ int refcount = ref_owner->reference_get_count();
+
+ if (refcount == 1) { // Remember the managed side holds a reference, hence 1 instead of 0 here
+ // If owner owner is no longer referenced by the unmanaged side,
+ // the managed instance takes responsibility of deleting the owner when GCed.
+
+ // Release the current strong handle and replace it with a weak handle.
+ uint32_t weak_gchandle = MonoGCHandle::make_weak_handle(gchandle->get_target());
+ gchandle->release();
+ gchandle->set_handle(weak_gchandle);
+
+ return false;
+ }
+
+ ref_dying = (refcount == 0);
+
+ return ref_dying;
+}
+
+ScriptInstance::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const {
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoMethod *method = top->get_method(p_method);
+
+ if (method) { // TODO should we reject static methods?
+ // TODO cache result
+ if (method->has_attribute(CACHED_CLASS(RemoteAttribute)))
+ return RPC_MODE_REMOTE;
+ if (method->has_attribute(CACHED_CLASS(SyncAttribute)))
+ return RPC_MODE_SYNC;
+ if (method->has_attribute(CACHED_CLASS(MasterAttribute)))
+ return RPC_MODE_MASTER;
+ if (method->has_attribute(CACHED_CLASS(SlaveAttribute)))
+ return RPC_MODE_SLAVE;
+ }
+
+ top = top->get_parent_class();
+ }
+
+ return RPC_MODE_DISABLED;
+}
+
+ScriptInstance::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const {
+
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ GDMonoField *field = top->get_field(p_variable);
+
+ if (field) { // TODO should we reject static fields?
+ // TODO cache result
+ if (field->has_attribute(CACHED_CLASS(RemoteAttribute)))
+ return RPC_MODE_REMOTE;
+ if (field->has_attribute(CACHED_CLASS(SyncAttribute)))
+ return RPC_MODE_SYNC;
+ if (field->has_attribute(CACHED_CLASS(MasterAttribute)))
+ return RPC_MODE_MASTER;
+ if (field->has_attribute(CACHED_CLASS(SlaveAttribute)))
+ return RPC_MODE_SLAVE;
+ }
+
+ top = top->get_parent_class();
+ }
+
+ return RPC_MODE_DISABLED;
+}
+
+void CSharpInstance::notification(int p_notification) {
+
+ Variant value = p_notification;
+ const Variant *args[1] = { &value };
+
+ call_multilevel(CACHED_STRING_NAME(_notification), args, 1);
+}
+
+Ref<Script> CSharpInstance::get_script() const {
+
+ return script;
+}
+
+ScriptLanguage *CSharpInstance::get_language() {
+
+ return CSharpLanguage::get_singleton();
+}
+
+CSharpInstance::CSharpInstance() {
+
+ owner = NULL;
+ base_ref = false;
+ ref_dying = false;
+}
+
+CSharpInstance::~CSharpInstance() {
+
+ if (gchandle.is_valid()) {
+ gchandle->release(); // Make sure it's released
+ }
+
+ if (base_ref && !ref_dying) { // it may be called from the owner's destructor
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!owner); // dunno, just in case
+#endif
+ _unreference_owner_unsafe();
+ }
+
+ if (script.is_valid() && owner) {
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->lock();
+#endif
+
+#ifdef DEBUG_ENABLED
+ // CSharpInstance must not be created unless it's going to be added to the list for sure
+ Set<Object *>::Element *match = script->instances.find(owner);
+ CRASH_COND(!match);
+ script->instances.erase(match);
+#else
+ script->instances.erase(owner);
+#endif
+
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->unlock();
+#endif
+ }
+}
+
+#ifdef TOOLS_ENABLED
+void CSharpScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
+
+ placeholders.erase(p_placeholder);
+}
+#endif
+
+#ifdef TOOLS_ENABLED
+void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) {
+
+ if (base_cache.is_valid()) {
+ base_cache->_update_exports_values(values, propnames);
+ }
+
+ for (Map<StringName, Variant>::Element *E = exported_members_defval_cache.front(); E; E = E->next()) {
+ values[E->key()] = E->get();
+ }
+
+ for (List<PropertyInfo>::Element *E = exported_members_cache.front(); E; E = E->next()) {
+ propnames.push_back(E->get());
+ }
+}
+#endif
+
+bool CSharpScript::_update_exports() {
+
+#ifdef TOOLS_ENABLED
+ if (!valid)
+ return false;
+
+ bool changed = false;
+
+ if (exports_invalidated) {
+ exports_invalidated = false;
+
+ changed = true;
+
+ member_info.clear();
+ exported_members_cache.clear();
+ exported_members_defval_cache.clear();
+
+ // We are creating a temporary new instance of the class here to get the default value
+ // TODO Workaround. Should be replaced with IL opcodes analysis
+
+ MonoObject *tmp_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_raw());
+
+ if (tmp_object) {
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(tmp_object, tmp_object); // FIXME WTF is this workaround
+
+ GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
+ MonoObject *ex = NULL;
+ ctor->invoke(tmp_object, NULL, &ex);
+
+ if (ex) {
+ ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
+ mono_print_unhandled_exception(ex);
+ tmp_object = NULL;
+ ERR_FAIL_V(false);
+ }
+ } else {
+ ERR_PRINT("Failed to create temporary MonoObject");
+ return false;
+ }
+
+ GDMonoClass *top = script_class;
+
+ while (top && top != native) {
+ const Vector<GDMonoField *> &fields = top->get_all_fields();
+
+ for (int i = 0; i < fields.size(); i++) {
+ GDMonoField *field = fields[i];
+
+ if (field->is_static()) {
+ if (field->has_attribute(CACHED_CLASS(ExportAttribute)))
+ ERR_PRINTS("Cannot export field because it is static: " + top->get_full_name() + "." + field->get_name());
+ continue;
+ }
+
+ String name = field->get_name();
+ StringName cname = name;
+
+ if (member_info.has(cname))
+ continue;
+
+ ManagedType field_type = field->get_type();
+ Variant::Type type = GDMonoMarshal::managed_to_variant_type(field_type);
+
+ if (field->has_attribute(CACHED_CLASS(ExportAttribute))) {
+ // Field has Export attribute
+ MonoObject *attr = field->get_attribute(CACHED_CLASS(ExportAttribute));
+
+ PropertyHint hint;
+ String hint_string;
+
+ if (type == Variant::NIL) {
+ ERR_PRINTS("Unknown type of exported field: " + top->get_full_name() + "." + field->get_name());
+ continue;
+ } else if (type == Variant::INT && field_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(field_type.type_class->get_raw())) {
+ type = Variant::INT;
+ hint = PROPERTY_HINT_ENUM;
+
+ Vector<MonoClassField *> fields = field_type.type_class->get_enum_fields();
+
+ for (int i = 0; i < fields.size(); i++) {
+ if (i > 0)
+ hint_string += ",";
+ hint_string += mono_field_get_name(fields[i]);
+ }
+ } else if (type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(field_type.type_class)) {
+ hint = PROPERTY_HINT_RESOURCE_TYPE;
+ hint_string = NATIVE_GDMONOCLASS_NAME(field_type.type_class);
+ } else {
+ hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
+ hint_string = CACHED_FIELD(ExportAttribute, hint_string)->get_string_value(attr);
+ }
+
+ PropertyInfo prop_info = PropertyInfo(type, name, hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE);
+
+ member_info[cname] = prop_info;
+ exported_members_cache.push_back(prop_info);
+
+ if (tmp_object) {
+ exported_members_defval_cache[cname] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object));
+ }
+ } else {
+ member_info[cname] = PropertyInfo(type, name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
+ }
+ }
+
+ top = top->get_parent_class();
+ }
+ }
+
+ if (placeholders.size()) {
+ // Update placeholders if any
+ Map<StringName, Variant> values;
+ List<PropertyInfo> propnames;
+ _update_exports_values(values, propnames);
+
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->update(propnames, values);
+ }
+ }
+
+ return changed;
+#endif
+ return false;
+}
+
+void CSharpScript::_clear() {
+
+ tool = false;
+ valid = false;
+
+ base = NULL;
+ native = NULL;
+ script_class = NULL;
+}
+
+Variant CSharpScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+
+ GDMonoClass *top = script_class;
+
+ while (top && top != native) {
+ GDMonoMethod *method = top->get_method(p_method, p_argcount);
+
+ if (method && method->is_static()) {
+ MonoObject *result = method->invoke(NULL, p_args);
+
+ if (result) {
+ return GDMonoMarshal::mono_object_to_variant(result, method->get_return_type());
+ } else {
+ return Variant();
+ }
+ }
+
+ top = top->get_parent_class();
+ }
+
+ // No static method found. Try regular instance calls
+ return Script::call(p_method, p_args, p_argcount, r_error);
+}
+
+void CSharpScript::_resource_path_changed() {
+
+ String path = get_path();
+
+ if (!path.empty()) {
+ name = get_path().get_file().get_basename();
+ }
+}
+
+bool CSharpScript::_get(const StringName &p_name, Variant &r_ret) const {
+
+ if (p_name == CSharpLanguage::singleton->string_names._script_source) {
+
+ r_ret = get_source_code();
+ return true;
+ }
+
+ return false;
+}
+
+bool CSharpScript::_set(const StringName &p_name, const Variant &p_value) {
+
+ if (p_name == CSharpLanguage::singleton->string_names._script_source) {
+
+ set_source_code(p_value);
+ reload();
+ return true;
+ }
+
+ return false;
+}
+
+void CSharpScript::_get_property_list(List<PropertyInfo> *p_properties) const {
+
+ p_properties->push_back(PropertyInfo(Variant::STRING, CSharpLanguage::singleton->string_names._script_source, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+}
+
+void CSharpScript::_bind_methods() {
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &CSharpScript::_new, MethodInfo(Variant::OBJECT, "new"));
+}
+
+Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class) {
+
+ // This method should not fail
+
+ CRASH_COND(!p_class);
+
+ Ref<CSharpScript> script = memnew(CSharpScript);
+
+ script->name = p_class->get_name();
+ script->script_class = p_class;
+ script->native = GDMonoUtils::get_class_native_base(script->script_class);
+
+ CRASH_COND(script->native == NULL);
+
+ GDMonoClass *base = script->script_class->get_parent_class();
+
+ if (base != script->native)
+ script->base = base;
+
+#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->script_class != script->native) {
+ GDMonoClass *native_top = script->native;
+ while (native_top) {
+ native_top->fetch_methods_with_godot_api_checks(script->native);
+
+ if (native_top == CACHED_CLASS(GodotObject))
+ break;
+
+ native_top = native_top->get_parent_class();
+ }
+ }
+#endif
+
+ script->script_class->fetch_methods_with_godot_api_checks(script->native);
+
+ // Need to fetch method from base classes as well
+ GDMonoClass *top = script->script_class;
+ while (top && top != script->native) {
+ top->fetch_methods_with_godot_api_checks(script->native);
+ top = top->get_parent_class();
+ }
+
+ return script;
+}
+
+bool CSharpScript::can_instance() const {
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ if (get_path().find("::") == -1) { // Ignore if built-in script. Can happen if the file is deleted...
+ if (_create_project_solution_if_needed()) {
+ CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(),
+ "Compile",
+ ProjectSettings::get_singleton()->globalize_path(get_path()));
+ } else {
+ ERR_PRINTS("Cannot add " + get_path() + " to the C# project because it could not be created.");
+ }
+ }
+ }
+#endif
+
+ return valid || (!tool && !ScriptServer::is_scripting_enabled());
+}
+
+StringName CSharpScript::get_instance_base_type() const {
+
+ if (native)
+ return native->get_name();
+ else
+ return StringName();
+}
+
+CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error) {
+
+ /* STEP 1, CREATE */
+
+ CSharpInstance *instance = memnew(CSharpInstance);
+ instance->base_ref = p_isref;
+ instance->script = Ref<CSharpScript>(this);
+ instance->owner = p_owner;
+ instance->owner->set_script_instance(instance);
+
+ if (instance->base_ref)
+ instance->_reference_owner_unsafe();
+
+ /* STEP 2, INITIALIZE AND CONSTRUCT */
+
+ MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, script_class->get_raw());
+
+ if (!mono_object) {
+ instance->script = Ref<CSharpScript>();
+ instance->owner->set_script_instance(NULL);
+ r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ ERR_EXPLAIN("Failed to allocate memory for the object");
+ ERR_FAIL_V(NULL);
+ }
+
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->lock();
+#endif
+
+ instances.insert(instance->owner);
+
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->unlock();
+#endif
+
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, instance->owner);
+
+ // Construct
+ GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
+ ctor->invoke(mono_object, p_args, NULL);
+
+ // Tie managed to unmanaged
+ instance->gchandle = MonoGCHandle::create_strong(mono_object);
+
+ /* STEP 3, PARTY */
+
+ //@TODO make thread safe
+ return instance;
+}
+
+Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+
+ if (!valid) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+
+ r_error.error = Variant::CallError::CALL_OK;
+ REF ref;
+ Object *owner = NULL;
+
+ ERR_FAIL_NULL_V(native, Variant());
+
+ owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native));
+
+ Reference *r = Object::cast_to<Reference>(owner);
+ if (r) {
+ ref = REF(r);
+ }
+
+ CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != NULL, r_error);
+ if (!instance) {
+ if (ref.is_null()) {
+ memdelete(owner); //no owner, sorry
+ }
+ return Variant();
+ }
+
+ if (ref.is_valid()) {
+ return ref;
+ } else {
+ return owner;
+ }
+}
+
+ScriptInstance *CSharpScript::instance_create(Object *p_this) {
+
+ if (!valid)
+ return NULL;
+
+ if (!tool && !ScriptServer::is_scripting_enabled()) {
+#ifdef TOOLS_ENABLED
+ PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this));
+ placeholders.insert(si);
+ _update_exports();
+ return si;
+#else
+ return NULL;
+#endif
+ }
+
+ if (native) {
+ String native_name = native->get_name();
+ if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
+ if (ScriptDebugger::get_singleton()) {
+ CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0, "Script inherits from native type '" + native_name + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
+ }
+ ERR_EXPLAIN("Script inherits from native type '" + native_name + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
+ ERR_FAIL_V(NULL);
+ }
+ }
+
+ Variant::CallError unchecked_error;
+ return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error);
+}
+
+bool CSharpScript::instance_has(const Object *p_this) const {
+
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->lock();
+#endif
+
+ bool ret = instances.has((Object *)p_this);
+
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->unlock();
+#endif
+
+ return ret;
+}
+
+bool CSharpScript::has_source_code() const {
+
+ return !source.empty();
+}
+
+String CSharpScript::get_source_code() const {
+
+ return source;
+}
+
+void CSharpScript::set_source_code(const String &p_code) {
+
+ if (source == p_code)
+ return;
+ source = p_code;
+#ifdef TOOLS_ENABLED
+ source_changed_cache = true;
+#endif
+}
+
+bool CSharpScript::has_method(const StringName &p_method) const {
+
+ return script_class->has_method(p_method);
+}
+
+Error CSharpScript::reload(bool p_keep_state) {
+
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->lock();
+#endif
+
+ bool has_instances = instances.size();
+
+#ifndef NO_THREADS
+ CSharpLanguage::singleton->lock->unlock();
+#endif
+
+ ERR_FAIL_COND_V(!p_keep_state && has_instances, ERR_ALREADY_IN_USE);
+
+ GDMonoAssembly *project_assembly = GDMono::get_singleton()->get_project_assembly();
+
+ if (project_assembly) {
+ script_class = project_assembly->get_object_derived_class(name);
+
+ if (!script_class) {
+ ERR_PRINTS("Cannot find class " + name + " for script " + get_path());
+ }
+#ifdef DEBUG_ENABLED
+ else if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." +
+ script_class->get_name() + " for script " + get_path() + "\n")
+ .utf8());
+ }
+#endif
+
+ valid = script_class != NULL;
+
+ if (script_class) {
+ tool = script_class->has_attribute(CACHED_CLASS(ToolAttribute));
+
+ native = GDMonoUtils::get_class_native_base(script_class);
+
+ CRASH_COND(native == NULL);
+
+ 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);
+
+ // 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();
+ }
+ }
+
+ return OK;
+ }
+
+ return ERR_FILE_MISSING_DEPENDENCIES;
+}
+
+ScriptLanguage *CSharpScript::get_language() const {
+
+ return CSharpLanguage::get_singleton();
+}
+
+bool CSharpScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
+
+#ifdef TOOLS_ENABLED
+
+ const Map<StringName, Variant>::Element *E = exported_members_defval_cache.find(p_property);
+ if (E) {
+ r_value = E->get();
+ return true;
+ }
+
+ if (base_cache.is_valid()) {
+ return base_cache->get_property_default_value(p_property, r_value);
+ }
+
+#endif
+ return false;
+}
+
+void CSharpScript::update_exports() {
+
+#ifdef TOOLS_ENABLED
+ _update_exports();
+#endif
+}
+
+Ref<Script> CSharpScript::get_base_script() const {
+
+ // TODO search in metadata file once we have it, not important any way?
+ return Ref<Script>();
+}
+
+void CSharpScript::get_script_property_list(List<PropertyInfo> *p_list) const {
+
+ for (Map<StringName, PropertyInfo>::Element *E = member_info.front(); E; E = E->next()) {
+ p_list->push_back(E->value());
+ }
+}
+
+int CSharpScript::get_member_line(const StringName &p_member) const {
+
+ // TODO omnisharp
+ return -1;
+}
+
+Error CSharpScript::load_source_code(const String &p_path) {
+
+ PoolVector<uint8_t> sourcef;
+ Error err;
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ int len = f->get_len();
+ sourcef.resize(len + 1);
+ PoolVector<uint8_t>::Write w = sourcef.write();
+ int r = f->get_buffer(w.ptr(), len);
+ f->close();
+ memdelete(f);
+ ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
+ w[len] = 0;
+
+ String s;
+ if (s.parse_utf8((const char *)w.ptr())) {
+
+ ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
+ ERR_FAIL_V(ERR_INVALID_DATA);
+ }
+
+ source = s;
+
+#ifdef TOOLS_ENABLED
+ source_changed_cache = true;
+#endif
+
+ return OK;
+}
+
+StringName CSharpScript::get_script_name() const {
+
+ return name;
+}
+
+CSharpScript::CSharpScript()
+ : script_list(this) {
+
+ _clear();
+
+#ifdef TOOLS_ENABLED
+ source_changed_cache = false;
+ exports_invalidated = true;
+#endif
+
+ _resource_path_changed();
+
+#ifdef DEBUG_ENABLED
+
+#ifndef NO_THREADS
+ CSharpLanguage::get_singleton()->lock->lock();
+#endif
+
+ CSharpLanguage::get_singleton()->script_list.add(&script_list);
+
+#ifndef NO_THREADS
+ CSharpLanguage::get_singleton()->lock->unlock();
+#endif
+
+#endif // DEBUG_ENABLED
+}
+
+CSharpScript::~CSharpScript() {
+
+#ifdef DEBUG_ENABLED
+
+#ifndef NO_THREADS
+ CSharpLanguage::get_singleton()->lock->lock();
+#endif
+
+ CSharpLanguage::get_singleton()->script_list.remove(&script_list);
+
+#ifndef NO_THREADS
+ CSharpLanguage::get_singleton()->lock->unlock();
+#endif
+
+#endif // DEBUG_ENABLED
+}
+
+/*************** RESOURCE ***************/
+
+RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error = ERR_FILE_CANT_OPEN;
+
+ // TODO ignore anything inside bin/ and obj/ in tools builds?
+
+ CSharpScript *script = memnew(CSharpScript);
+
+ Ref<CSharpScript> scriptres(script);
+
+#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
+ Error err = script->load_source_code(p_path);
+ ERR_FAIL_COND_V(err != OK, RES());
+#endif
+
+ script->set_path(p_original_path);
+
+#ifndef TOOLS_ENABLED
+
+#ifdef DEBUG_ENABLED
+ // User is responsible for thread attach/detach
+ ERR_EXPLAIN("Thread is not attached");
+ CRASH_COND(mono_domain_get() == NULL);
+#endif
+
+#else
+ if (Engine::get_singleton()->is_editor_hint() && mono_domain_get() == NULL) {
+
+ CRASH_COND(Thread::get_caller_id() == Thread::get_main_id());
+
+ // Thread is not attached, but we will make an exception in this case
+ // because this may be called by one of the editor's worker threads.
+ // Attach this thread temporarily to reload the script.
+
+ MonoThread *mono_thread = mono_thread_attach(SCRIPTS_DOMAIN);
+ CRASH_COND(mono_thread == NULL);
+ script->reload();
+ mono_thread_detach(mono_thread);
+
+ } else // just reload it normally
+#endif
+ script->reload();
+
+ if (r_error)
+ *r_error = OK;
+
+ return scriptres;
+}
+
+void ResourceFormatLoaderCSharpScript::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("cs");
+}
+
+bool ResourceFormatLoaderCSharpScript::handles_type(const String &p_type) const {
+
+ return p_type == "Script" || p_type == CSharpLanguage::get_singleton()->get_type();
+}
+
+String ResourceFormatLoaderCSharpScript::get_resource_type(const String &p_path) const {
+
+ return p_path.get_extension().to_lower() == "cs" ? CSharpLanguage::get_singleton()->get_type() : "";
+}
+
+Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+
+ Ref<CSharpScript> sqscr = p_resource;
+ ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
+
+ String source = sqscr->get_source_code();
+
+#ifdef TOOLS_ENABLED
+ if (!FileAccess::exists(p_path)) {
+ // The file does not yet exists, let's assume the user just created this script
+
+ if (_create_project_solution_if_needed()) {
+ CSharpProject::add_item(GodotSharpDirs::get_project_csproj_path(),
+ "Compile",
+ ProjectSettings::get_singleton()->globalize_path(p_path));
+ } else {
+ ERR_PRINTS("Cannot add " + p_path + " to the C# project because it could not be created.");
+ }
+ }
+#endif
+
+ Error err;
+ FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(err, err);
+
+ file->store_string(source);
+
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ memdelete(file);
+ return ERR_CANT_CREATE;
+ }
+
+ file->close();
+ memdelete(file);
+
+ if (ScriptServer::is_reload_scripts_on_save_enabled()) {
+ CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false);
+ }
+
+ return OK;
+}
+
+void ResourceFormatSaverCSharpScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+
+ if (Object::cast_to<CSharpScript>(p_resource.ptr())) {
+ p_extensions->push_back("cs");
+ }
+}
+
+bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const {
+
+ return Object::cast_to<CSharpScript>(p_resource.ptr()) != NULL;
+}
+
+CSharpLanguage::StringNameCache::StringNameCache() {
+
+ _signal_callback = StaticCString::create("_signal_callback");
+ _set = StaticCString::create("_set");
+ _get = StaticCString::create("_get");
+ _notification = StaticCString::create("_notification");
+ _script_source = StaticCString::create("script/source");
+ dotctor = StaticCString::create(".ctor");
+}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
new file mode 100644
index 0000000000..255665b495
--- /dev/null
+++ b/modules/mono/csharp_script.h
@@ -0,0 +1,347 @@
+/*************************************************************************/
+/* csharp_script.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CSHARP_SCRIPT_H
+#define CSHARP_SCRIPT_H
+
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "script_language.h"
+#include "self_list.h"
+
+#include "mono_gc_handle.h"
+#include "mono_gd/gd_mono.h"
+#include "mono_gd/gd_mono_header.h"
+#include "mono_gd/gd_mono_internals.h"
+
+class CSharpScript;
+class CSharpInstance;
+class CSharpLanguage;
+
+#ifdef NO_SAFE_CAST
+template <typename TScriptInstance, typename TScriptLanguage>
+TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
+ return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : NULL;
+}
+#else
+template <typename TScriptInstance, typename TScriptLanguage>
+TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
+ return dynamic_cast<TScriptInstance *>(p_inst);
+}
+#endif
+
+#define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst))
+
+class CSharpScript : public Script {
+
+ GDCLASS(CSharpScript, Script)
+
+ friend class CSharpInstance;
+ friend class CSharpLanguage;
+ friend class CSharpScriptDepSort;
+
+ bool tool;
+ bool valid;
+
+ bool builtin;
+
+ GDMonoClass *base;
+ GDMonoClass *native;
+ GDMonoClass *script_class;
+
+ Ref<CSharpScript> base_cache; // TODO what's this for?
+
+ Set<Object *> instances;
+
+ String source;
+ StringName name;
+
+ SelfList<CSharpScript> script_list;
+
+#ifdef TOOLS_ENABLED
+ List<PropertyInfo> exported_members_cache; // members_cache
+ Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
+ Set<PlaceHolderScriptInstance *> placeholders;
+ bool source_changed_cache;
+ bool exports_invalidated;
+
+ void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
+ virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
+#endif
+
+#ifdef DEBUG_ENABLED
+ Map<ObjectID, List<Pair<StringName, Variant> > > pending_reload_state;
+#endif
+
+ Map<StringName, PropertyInfo> member_info;
+
+ void _clear();
+
+ bool _update_exports();
+ CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
+ Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+
+ // 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);
+
+protected:
+ static void _bind_methods();
+
+ Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+ virtual void _resource_path_changed();
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ bool _set(const StringName &p_name, const Variant &p_value);
+ void _get_property_list(List<PropertyInfo> *p_properties) const;
+
+public:
+ virtual bool can_instance() const;
+ virtual StringName get_instance_base_type() const;
+ virtual ScriptInstance *instance_create(Object *p_this);
+ virtual bool instance_has(const Object *p_this) const;
+
+ virtual bool has_source_code() const;
+ virtual String get_source_code() const;
+ virtual void set_source_code(const String &p_code);
+
+ virtual Error reload(bool p_keep_state = false);
+
+ /* TODO */ virtual bool has_script_signal(const StringName &p_signal) const { return false; }
+ /* TODO */ virtual void get_script_signal_list(List<MethodInfo> *r_signals) const {}
+
+ /* TODO */ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const;
+ virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
+ virtual void update_exports();
+
+ virtual bool is_tool() const { return tool; }
+ virtual Ref<Script> get_base_script() const;
+ virtual ScriptLanguage *get_language() const;
+
+ /* TODO */ virtual void get_script_method_list(List<MethodInfo> *p_list) const {}
+ bool has_method(const StringName &p_method) const;
+ /* TODO */ MethodInfo get_method_info(const StringName &p_method) const { return MethodInfo(); }
+
+ virtual int get_member_line(const StringName &p_member) const;
+
+ Error load_source_code(const String &p_path);
+
+ StringName get_script_name() const;
+
+ CSharpScript();
+ ~CSharpScript();
+};
+
+class CSharpInstance : public ScriptInstance {
+
+ friend class CSharpScript;
+ friend class CSharpLanguage;
+ Object *owner;
+ Ref<CSharpScript> script;
+ Ref<MonoGCHandle> gchandle;
+ bool base_ref;
+ bool ref_dying;
+
+ void _ml_call_reversed(GDMonoClass *klass, const StringName &p_method, const Variant **p_args, int p_argcount);
+
+ void _reference_owner_unsafe();
+ void _unreference_owner_unsafe();
+
+ // Do not use unless you know what you are doing
+ friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
+ static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const Ref<MonoGCHandle> &p_gchandle);
+
+public:
+ MonoObject *get_mono_object() const;
+
+ virtual bool set(const StringName &p_name, const Variant &p_value);
+ virtual bool get(const StringName &p_name, Variant &r_ret) const;
+ virtual void get_property_list(List<PropertyInfo> *p_properties) const;
+ virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const;
+
+ /* TODO */ virtual void get_method_list(List<MethodInfo> *p_list) const {}
+ virtual bool has_method(const StringName &p_method) const;
+ virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+ virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
+ virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
+
+ void mono_object_disposed();
+
+ void refcount_incremented();
+ bool refcount_decremented();
+
+ RPCMode get_rpc_mode(const StringName &p_method) const;
+ RPCMode get_rset_mode(const StringName &p_variable) const;
+
+ virtual void notification(int p_notification);
+
+ virtual Ref<Script> get_script() const;
+
+ virtual ScriptLanguage *get_language();
+
+ CSharpInstance();
+ ~CSharpInstance();
+};
+
+class CSharpLanguage : public ScriptLanguage {
+
+ friend class CSharpScript;
+ friend class CSharpInstance;
+
+ static CSharpLanguage *singleton;
+
+ GDMono *gdmono;
+ SelfList<CSharpScript>::List script_list;
+
+ Mutex *lock;
+ Mutex *script_bind_lock;
+
+ Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > > to_reload;
+
+ Map<Object *, Ref<MonoGCHandle> > gchandle_bindings;
+
+ struct StringNameCache {
+
+ StringName _signal_callback;
+ StringName _set;
+ StringName _get;
+ StringName _notification;
+ StringName _script_source;
+ StringName dotctor; // .ctor
+
+ StringNameCache();
+ };
+
+ int lang_idx;
+
+public:
+ StringNameCache string_names;
+
+ _FORCE_INLINE_ int get_language_index() { return lang_idx; }
+ void set_language_index(int p_idx);
+
+ _FORCE_INLINE_ const StringNameCache &get_string_names() { return string_names; }
+
+ _FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; }
+
+ bool debug_break(const String &p_error, bool p_allow_continue = true);
+ bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
+
+#ifdef TOOLS_ENABLED
+ void reload_assemblies_if_needed(bool p_soft_reload);
+#endif
+
+ virtual String get_name() const;
+
+ /* LANGUAGE FUNCTIONS */
+ virtual String get_type() const;
+ virtual String get_extension() const;
+ virtual Error execute_file(const String &p_path);
+ virtual void init();
+ virtual void finish();
+
+ /* EDITOR FUNCTIONS */
+ virtual void get_reserved_words(List<String> *p_words) const;
+ virtual void get_comment_delimiters(List<String> *p_delimiters) const;
+ virtual void get_string_delimiters(List<String> *p_delimiters) const;
+ virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
+ virtual bool is_using_templates();
+ virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
+ /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { return true; }
+ virtual Script *create_script() const;
+ virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() const;
+ /* TODO? */ virtual int find_function(const String &p_function, const String &p_code) const { return -1; }
+ virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
+ /* TODO? */ Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { return ERR_UNAVAILABLE; }
+ virtual String _get_indentation() const;
+ /* TODO? */ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {}
+ /* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {}
+
+ /* DEBUGGER FUNCTIONS */
+ /* TODO */ virtual String debug_get_error() const { return ""; }
+ /* TODO */ virtual int debug_get_stack_level_count() const { return 1; }
+ /* TODO */ virtual int debug_get_stack_level_line(int p_level) const { return 1; }
+ /* TODO */ virtual String debug_get_stack_level_function(int p_level) const { return ""; }
+ /* TODO */ virtual String debug_get_stack_level_source(int p_level) const { return ""; }
+ /* TODO */ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
+ /* TODO */ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
+ /* TODO */ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {}
+ /* TODO */ virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { return ""; }
+ /* TODO */ virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); }
+
+ /* PROFILING FUNCTIONS */
+ /* TODO */ virtual void profiling_start() {}
+ /* TODO */ virtual void profiling_stop() {}
+ /* TODO */ virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) { return 0; }
+ /* TODO */ virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) { return 0; }
+
+ virtual void frame();
+
+ /* TODO? */ virtual void get_public_functions(List<MethodInfo> *p_functions) const {}
+ /* TODO? */ virtual void get_public_constants(List<Pair<String, Variant> > *p_constants) const {}
+
+ virtual void reload_all_scripts();
+ virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload);
+
+ /* LOADER FUNCTIONS */
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+
+#ifdef TOOLS_ENABLED
+ virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col);
+ virtual bool overrides_external_editor();
+#endif
+
+ /* THREAD ATTACHING */
+ virtual void thread_enter();
+ virtual void thread_exit();
+
+ // Don't use these. I'm watching you
+ virtual void *alloc_instance_binding_data(Object *p_object);
+ virtual void free_instance_binding_data(void *p_data);
+
+ CSharpLanguage();
+ ~CSharpLanguage();
+};
+
+class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class ResourceFormatSaverCSharpScript : public ResourceFormatSaver {
+public:
+ virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const RES &p_resource) const;
+};
+
+#endif // CSHARP_SCRIPT_H
diff --git a/modules/mono/doc_classes/@C#.xml b/modules/mono/doc_classes/@C#.xml
new file mode 100644
index 0000000000..487ba9835f
--- /dev/null
+++ b/modules/mono/doc_classes/@C#.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="@C#" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
new file mode 100644
index 0000000000..5f21c9774d
--- /dev/null
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="CSharpScript" inherits="Script" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ <method name="new" qualifiers="vararg">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
new file mode 100644
index 0000000000..e7e06ddd8f
--- /dev/null
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GodotSharp" inherits="Object" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ <method name="attach_thread">
+ <return type="void">
+ </return>
+ <description>
+ Attaches the current thread to the mono runtime.
+ </description>
+ </method>
+ <method name="detach_thread">
+ <return type="void">
+ </return>
+ <description>
+ Detaches the current thread from the mono runtime.
+ </description>
+ </method>
+ <method name="is_domain_loaded">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether the scripts domain is loaded.
+ </description>
+ </method>
+ <method name="is_finalizing_domain">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether the scripts domain is being finalized.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
new file mode 100644
index 0000000000..04da0600cc
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs
@@ -0,0 +1,369 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+using Microsoft.Build.Framework;
+
+namespace GodotSharpTools.Build
+{
+ public class BuildInstance : IDisposable
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private extern static void godot_icall_BuildInstance_get_MSBuildInfo(ref string msbuildPath, ref string frameworkPath);
+
+ private struct MSBuildInfo
+ {
+ public string path;
+ public string frameworkPathOverride;
+ }
+
+ private static MSBuildInfo GetMSBuildInfo()
+ {
+ MSBuildInfo msbuildInfo = new MSBuildInfo();
+
+ godot_icall_BuildInstance_get_MSBuildInfo(ref msbuildInfo.path, ref msbuildInfo.frameworkPathOverride);
+
+ if (msbuildInfo.path == null)
+ throw new FileNotFoundException("Cannot find the MSBuild executable.");
+
+ return msbuildInfo;
+ }
+
+ private string solution;
+ private string config;
+
+ private Process process;
+
+ private int exitCode;
+ public int ExitCode { get { return exitCode; } }
+
+ public bool IsRunning { get { return process != null && !process.HasExited; } }
+
+ public BuildInstance(string solution, string config)
+ {
+ this.solution = solution;
+ this.config = config;
+ }
+
+ public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
+ {
+ MSBuildInfo msbuildInfo = GetMSBuildInfo();
+
+ List<string> customPropertiesList = new List<string>();
+
+ if (customProperties != null)
+ customPropertiesList.AddRange(customProperties);
+
+ if (msbuildInfo.frameworkPathOverride != null)
+ customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.frameworkPathOverride);
+
+ string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
+
+ ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.path, compilerArgs);
+
+ // No console output, thanks
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
+ startInfo.UseShellExecute = false;
+
+ // Needed when running from Developer Command Prompt for VS
+ RemovePlatformVariable(startInfo.EnvironmentVariables);
+
+ using (Process process = new Process())
+ {
+ process.StartInfo = startInfo;
+
+ process.Start();
+
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+
+ process.WaitForExit();
+
+ exitCode = process.ExitCode;
+ }
+
+ return true;
+ }
+
+ public bool BuildAsync(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null)
+ {
+ if (process != null)
+ throw new InvalidOperationException("Already in use");
+
+ MSBuildInfo msbuildInfo = GetMSBuildInfo();
+
+ List<string> customPropertiesList = new List<string>();
+
+ if (customProperties != null)
+ customPropertiesList.AddRange(customProperties);
+
+ if (msbuildInfo.frameworkPathOverride.Length > 0)
+ customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.frameworkPathOverride);
+
+ string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList);
+
+ ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.path, compilerArgs);
+
+ // No console output, thanks
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
+ startInfo.UseShellExecute = false;
+
+ // Needed when running from Developer Command Prompt for VS
+ RemovePlatformVariable(startInfo.EnvironmentVariables);
+
+ process = new Process();
+ process.StartInfo = startInfo;
+ process.EnableRaisingEvents = true;
+ process.Exited += new EventHandler(BuildProcess_Exited);
+
+ process.Start();
+
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+
+ return true;
+ }
+
+ private string BuildArguments(string loggerAssemblyPath, string loggerOutputDir, List<string> customProperties)
+ {
+ string arguments = string.Format(@"""{0}"" /v:normal /t:Build ""/p:{1}"" ""/l:{2},{3};{4}""",
+ solution,
+ "Configuration=" + config,
+ typeof(GodotBuildLogger).FullName,
+ loggerAssemblyPath,
+ loggerOutputDir
+ );
+
+ foreach (string customProperty in customProperties)
+ {
+ arguments += " \"/p:" + customProperty + "\"";
+ }
+
+ return arguments;
+ }
+
+ private void RemovePlatformVariable(StringDictionary environmentVariables)
+ {
+ // EnvironmentVariables is case sensitive? Seriously?
+
+ List<string> platformEnvironmentVariables = new List<string>();
+
+ foreach (string env in environmentVariables.Keys)
+ {
+ if (env.ToUpper() == "PLATFORM")
+ platformEnvironmentVariables.Add(env);
+ }
+
+ foreach (string env in platformEnvironmentVariables)
+ environmentVariables.Remove(env);
+ }
+
+ private void BuildProcess_Exited(object sender, System.EventArgs e)
+ {
+ exitCode = process.ExitCode;
+
+ godot_icall_BuildInstance_ExitCallback(solution, config, exitCode);
+
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ if (process != null)
+ {
+ process.Dispose();
+ process = null;
+ }
+ }
+ }
+
+ public class GodotBuildLogger : ILogger
+ {
+ public string Parameters { get; set; }
+ public LoggerVerbosity Verbosity { get; set; }
+
+ public void Initialize(IEventSource eventSource)
+ {
+ if (null == Parameters)
+ throw new LoggerException("Log directory was not set.");
+
+ string[] parameters = Parameters.Split(';');
+
+ string logDir = parameters[0];
+
+ if (String.IsNullOrEmpty(logDir))
+ throw new LoggerException("Log directory was not set.");
+
+ if (parameters.Length > 1)
+ throw new LoggerException("Too many parameters passed.");
+
+ string logFile = Path.Combine(logDir, "msbuild_log.txt");
+ string issuesFile = Path.Combine(logDir, "msbuild_issues.csv");
+
+ try
+ {
+ if (!Directory.Exists(logDir))
+ Directory.CreateDirectory(logDir);
+
+ this.logStreamWriter = new StreamWriter(logFile);
+ this.issuesStreamWriter = new StreamWriter(issuesFile);
+ }
+ catch (Exception ex)
+ {
+ if
+ (
+ ex is UnauthorizedAccessException
+ || ex is ArgumentNullException
+ || ex is PathTooLongException
+ || ex is DirectoryNotFoundException
+ || ex is NotSupportedException
+ || ex is ArgumentException
+ || ex is SecurityException
+ || ex is IOException
+ )
+ {
+ throw new LoggerException("Failed to create log file: " + ex.Message);
+ }
+ else
+ {
+ // Unexpected failure
+ throw;
+ }
+ }
+
+ eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
+ eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted);
+ eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised);
+ eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
+ eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
+ eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
+ }
+
+ void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
+ {
+ string line = String.Format("{0}({1},{2}): error {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message);
+
+ if (e.ProjectFile.Length > 0)
+ line += string.Format(" [{0}]", e.ProjectFile);
+
+ WriteLine(line);
+
+ string errorLine = String.Format(@"error,{0},{1},{2},{3},{4},{5}",
+ e.File.CsvEscape(), e.LineNumber, e.ColumnNumber,
+ e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile.CsvEscape());
+ issuesStreamWriter.WriteLine(errorLine);
+ }
+
+ void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
+ {
+ string line = String.Format("{0}({1},{2}): warning {3}: {4}", e.File, e.LineNumber, e.ColumnNumber, e.Code, e.Message, e.ProjectFile);
+
+ if (e.ProjectFile != null && e.ProjectFile.Length > 0)
+ line += string.Format(" [{0}]", e.ProjectFile);
+
+ WriteLine(line);
+
+ string warningLine = String.Format(@"warning,{0},{1},{2},{3},{4},{5}",
+ e.File.CsvEscape(), e.LineNumber, e.ColumnNumber,
+ e.Code.CsvEscape(), e.Message.CsvEscape(), e.ProjectFile != null ? e.ProjectFile.CsvEscape() : string.Empty);
+ issuesStreamWriter.WriteLine(warningLine);
+ }
+
+ void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
+ {
+ // BuildMessageEventArgs adds Importance to BuildEventArgs
+ // Let's take account of the verbosity setting we've been passed in deciding whether to log the message
+ if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal))
+ || (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal))
+ || (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed))
+ )
+ {
+ WriteLineWithSenderAndMessage(String.Empty, e);
+ }
+ }
+
+ void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
+ {
+ // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
+ // To keep this log clean, this logger will ignore these events.
+ }
+
+ void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
+ {
+ WriteLine(e.Message);
+ indent++;
+ }
+
+ 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", true /*ignore case*/))
+ {
+ // 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)
+ /// </summary>
+ private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
+ {
+ if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
+ {
+ // Well, if the sender name is MSBuild, let's leave it out for prettiness
+ WriteLine(line + e.Message);
+ }
+ else
+ {
+ WriteLine(e.SenderName + ": " + line + e.Message);
+ }
+ }
+
+ private void WriteLine(string line)
+ {
+ for (int i = indent; i > 0; i--)
+ {
+ logStreamWriter.Write("\t");
+ }
+ logStreamWriter.WriteLine(line);
+ }
+
+ public void Shutdown()
+ {
+ logStreamWriter.Close();
+ issuesStreamWriter.Close();
+ }
+
+ public bool IsVerbosityAtLeast(LoggerVerbosity checkVerbosity)
+ {
+ return this.Verbosity >= checkVerbosity;
+ }
+
+ private StreamWriter logStreamWriter;
+ private StreamWriter issuesStreamWriter;
+ private int indent;
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs b/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs
new file mode 100644
index 0000000000..303be3b732
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/Editor/MonoDevelopInstance.cs
@@ -0,0 +1,58 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace GodotSharpTools.Editor
+{
+ public class MonoDevelopInstance
+ {
+ private Process process;
+ private string solutionFile;
+
+ public void Execute(string[] files)
+ {
+ bool newWindow = process == null || process.HasExited;
+
+ List<string> args = new List<string>();
+
+ args.Add("--ipc-tcp");
+
+ if (newWindow)
+ args.Add("\"" + Path.GetFullPath(solutionFile) + "\"");
+
+ foreach (var file in files)
+ {
+ int semicolonIndex = file.IndexOf(';');
+
+ string filePath = semicolonIndex < 0 ? file : file.Substring(0, semicolonIndex);
+ string cursor = semicolonIndex < 0 ? string.Empty : file.Substring(semicolonIndex);
+
+ args.Add("\"" + Path.GetFullPath(filePath.NormalizePath()) + cursor + "\"");
+ }
+
+ if (newWindow)
+ {
+ ProcessStartInfo startInfo = new ProcessStartInfo(MonoDevelopFile, string.Join(" ", args));
+ process = Process.Start(startInfo);
+ }
+ else
+ {
+ Process.Start(MonoDevelopFile, string.Join(" ", args));
+ }
+ }
+
+ public MonoDevelopInstance(string solutionFile)
+ {
+ this.solutionFile = solutionFile;
+ }
+
+ private static string MonoDevelopFile
+ {
+ get
+ {
+ return "monodevelop";
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
new file mode 100644
index 0000000000..981083a3c2
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>GodotSharpTools</RootNamespace>
+ <AssemblyName>GodotSharpTools</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="Microsoft.Build" />
+ <Reference Include="Microsoft.Build.Framework" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="StringExtensions.cs" />
+ <Compile Include="Build\BuildSystem.cs" />
+ <Compile Include="Editor\MonoDevelopInstance.cs" />
+ <Compile Include="Project\ProjectExtensions.cs" />
+ <Compile Include="Project\ProjectGenerator.cs" />
+ <Compile Include="Project\ProjectUtils.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln b/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln
new file mode 100644
index 0000000000..5f7d0e8a39
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.sln
@@ -0,0 +1,17 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpTools", "GodotSharpTools.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs b/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs
new file mode 100644
index 0000000000..0cbafdc20d
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.userprefs
@@ -0,0 +1,14 @@
+<Properties StartupItem="GodotSharpTools.csproj">
+ <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
+ <MonoDevelop.Ide.Workbench ActiveDocument="Build/BuildSystem.cs">
+ <Files>
+ <File FileName="Build/ProjectExtensions.cs" Line="1" Column="1" />
+ <File FileName="Build/ProjectGenerator.cs" Line="1" Column="1" />
+ <File FileName="Build/BuildSystem.cs" Line="37" Column="14" />
+ </Files>
+ </MonoDevelop.Ide.Workbench>
+ <MonoDevelop.Ide.DebuggingService.Breakpoints>
+ <BreakpointStore />
+ </MonoDevelop.Ide.DebuggingService.Breakpoints>
+ <MonoDevelop.Ide.DebuggingService.PinnedWatches />
+</Properties> \ No newline at end of file
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs
new file mode 100644
index 0000000000..f00ec5a2ad
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/Project/ProjectExtensions.cs
@@ -0,0 +1,52 @@
+using System;
+using Microsoft.Build.Construction;
+
+namespace GodotSharpTools.Project
+{
+ public static class ProjectExtensions
+ {
+ public static bool HasItem(this ProjectRootElement root, string itemType, string include)
+ {
+ string includeNormalized = include.NormalizePath();
+
+ foreach (var itemGroup in root.ItemGroups)
+ {
+ if (itemGroup.Condition.Length != 0)
+ continue;
+
+ foreach (var item in itemGroup.Items)
+ {
+ if (item.ItemType == itemType)
+ {
+ if (item.Include.NormalizePath() == includeNormalized)
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static bool AddItemChecked(this ProjectRootElement root, string itemType, string include)
+ {
+ if (!root.HasItem(itemType, include))
+ {
+ root.AddItem(itemType, include);
+ return true;
+ }
+
+ return false;
+ }
+
+ public static Guid GetGuid(this ProjectRootElement root)
+ {
+ foreach (var property in root.Properties)
+ {
+ if (property.Name == "ProjectGuid")
+ return Guid.Parse(property.Value);
+ }
+
+ return Guid.Empty;
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
new file mode 100644
index 0000000000..6bf54a0156
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs
@@ -0,0 +1,216 @@
+using System;
+using System.IO;
+using Microsoft.Build.Construction;
+
+namespace GodotSharpTools.Project
+{
+ public static class ProjectGenerator
+ {
+ public static string GenCoreApiProject(string dir, string[] compileItems)
+ {
+ string path = Path.Combine(dir, CoreApiProject + ".csproj");
+
+ ProjectPropertyGroupElement mainGroup;
+ var root = CreateLibraryProject(CoreApiProject, out mainGroup);
+
+ mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
+ mainGroup.SetProperty("RootNamespace", "Godot");
+
+ GenAssemblyInfoFile(root, dir, CoreApiProject,
+ new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProject + "\")]" },
+ new string[] { "System.Runtime.CompilerServices" });
+
+ foreach (var item in compileItems)
+ {
+ root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
+ }
+
+ root.Save(path);
+
+ return root.GetGuid().ToString().ToUpper();
+ }
+
+ public static string GenEditorApiProject(string dir, string coreApiHintPath, string[] compileItems)
+ {
+ string path = Path.Combine(dir, EditorApiProject + ".csproj");
+
+ ProjectPropertyGroupElement mainGroup;
+ var root = CreateLibraryProject(EditorApiProject, out mainGroup);
+
+ mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
+ mainGroup.SetProperty("RootNamespace", "Godot");
+
+ GenAssemblyInfoFile(root, dir, EditorApiProject);
+
+ foreach (var item in compileItems)
+ {
+ root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
+ }
+
+ var coreApiRef = root.AddItem("Reference", CoreApiProject);
+ coreApiRef.AddMetadata("HintPath", coreApiHintPath);
+ coreApiRef.AddMetadata("Private", "False");
+
+ root.Save(path);
+
+ return root.GetGuid().ToString().ToUpper();
+ }
+
+ public static string GenGameProject(string dir, string name, string[] compileItems)
+ {
+ string path = Path.Combine(dir, name + ".csproj");
+
+ ProjectPropertyGroupElement mainGroup;
+ var root = CreateLibraryProject(name, out mainGroup);
+
+ mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)"));
+ mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj"));
+ mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)"));
+
+ var toolsGroup = root.AddPropertyGroup();
+ toolsGroup.Condition = " '$(Configuration)|$(Platform)' == 'Tools|AnyCPU' ";
+ toolsGroup.AddProperty("DebugSymbols", "true");
+ toolsGroup.AddProperty("DebugType", "full");
+ toolsGroup.AddProperty("Optimize", "false");
+ toolsGroup.AddProperty("DefineConstants", "DEBUG;TOOLS;");
+ toolsGroup.AddProperty("ErrorReport", "prompt");
+ toolsGroup.AddProperty("WarningLevel", "4");
+ toolsGroup.AddProperty("ConsolePause", "false");
+
+ var coreApiRef = root.AddItem("Reference", CoreApiProject);
+ coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProject + ".dll"));
+ coreApiRef.AddMetadata("Private", "False");
+
+ var editorApiRef = root.AddItem("Reference", EditorApiProject);
+ editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
+ editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProject + ".dll"));
+ editorApiRef.AddMetadata("Private", "False");
+
+ GenAssemblyInfoFile(root, dir, name);
+
+ foreach (var item in compileItems)
+ {
+ root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
+ }
+
+ root.Save(path);
+
+ return root.GetGuid().ToString().ToUpper();
+ }
+
+ public static void GenAssemblyInfoFile(ProjectRootElement root, string dir, string name, string[] assemblyLines = null, string[] usingDirectives = null)
+ {
+
+ string propertiesDir = Path.Combine(dir, "Properties");
+ if (!Directory.Exists(propertiesDir))
+ Directory.CreateDirectory(propertiesDir);
+
+ string usingDirectivesText = string.Empty;
+
+ if (usingDirectives != null)
+ {
+ foreach (var usingDirective in usingDirectives)
+ usingDirectivesText += "\nusing " + usingDirective + ";";
+ }
+
+ string assemblyLinesText = string.Empty;
+
+ if (assemblyLines != null)
+ {
+ foreach (var assemblyLine in assemblyLines)
+ assemblyLinesText += string.Join("\n", assemblyLines) + "\n";
+ }
+
+ string content = string.Format(assemblyInfoTemplate, usingDirectivesText, name, assemblyLinesText);
+
+ string assemblyInfoFile = Path.Combine(propertiesDir, "AssemblyInfo.cs");
+
+ File.WriteAllText(assemblyInfoFile, content);
+
+ root.AddItem("Compile", assemblyInfoFile.RelativeToPath(dir).Replace("/", "\\"));
+ }
+
+ public static ProjectRootElement CreateLibraryProject(string name, out ProjectPropertyGroupElement mainGroup)
+ {
+ var root = ProjectRootElement.Create();
+ root.DefaultTargets = "Build";
+
+ mainGroup = root.AddPropertyGroup();
+ mainGroup.AddProperty("Configuration", "Debug").Condition = " '$(Configuration)' == '' ";
+ mainGroup.AddProperty("Platform", "AnyCPU").Condition = " '$(Platform)' == '' ";
+ mainGroup.AddProperty("ProjectGuid", "{" + Guid.NewGuid().ToString().ToUpper() + "}");
+ mainGroup.AddProperty("OutputType", "Library");
+ mainGroup.AddProperty("OutputPath", Path.Combine("bin", "$(Configuration)"));
+ mainGroup.AddProperty("RootNamespace", name);
+ mainGroup.AddProperty("AssemblyName", name);
+ mainGroup.AddProperty("TargetFrameworkVersion", "v4.5");
+
+ var debugGroup = root.AddPropertyGroup();
+ debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ";
+ debugGroup.AddProperty("DebugSymbols", "true");
+ debugGroup.AddProperty("DebugType", "full");
+ debugGroup.AddProperty("Optimize", "false");
+ debugGroup.AddProperty("DefineConstants", "DEBUG;");
+ debugGroup.AddProperty("ErrorReport", "prompt");
+ debugGroup.AddProperty("WarningLevel", "4");
+ debugGroup.AddProperty("ConsolePause", "false");
+
+ var releaseGroup = root.AddPropertyGroup();
+ releaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ";
+ releaseGroup.AddProperty("DebugType", "full");
+ releaseGroup.AddProperty("Optimize", "true");
+ releaseGroup.AddProperty("ErrorReport", "prompt");
+ releaseGroup.AddProperty("WarningLevel", "4");
+ releaseGroup.AddProperty("ConsolePause", "false");
+
+ // References
+ var referenceGroup = root.AddItemGroup();
+ referenceGroup.AddItem("Reference", "System");
+
+ root.AddImport(Path.Combine("$(MSBuildBinPath)", "Microsoft.CSharp.targets").Replace("/", "\\"));
+
+ return root;
+ }
+
+ private static void AddItems(ProjectRootElement elem, string groupName, params string[] items)
+ {
+ var group = elem.AddItemGroup();
+
+ foreach (var item in items)
+ {
+ group.AddItem(groupName, item);
+ }
+ }
+
+ public const string CoreApiProject = "GodotSharp";
+ public const string EditorApiProject = "GodotSharpEditor";
+
+ private const string assemblyInfoTemplate =
+@"using System.Reflection;{0}
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle(""{1}"")]
+[assembly: AssemblyDescription("""")]
+[assembly: AssemblyConfiguration("""")]
+[assembly: AssemblyCompany("""")]
+[assembly: AssemblyProduct("""")]
+[assembly: AssemblyCopyright("""")]
+[assembly: AssemblyTrademark("""")]
+[assembly: AssemblyCulture("""")]
+
+// The assembly version has the format ""{{Major}}.{{Minor}}.{{Build}}.{{Revision}}"".
+// The form ""{{Major}}.{{Minor}}.*"" will automatically update the build and revision,
+// and ""{{Major}}.{{Minor}}.{{Build}}.*"" will update just the revision.
+
+[assembly: AssemblyVersion(""1.0.*"")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("""")]
+{2}";
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
new file mode 100644
index 0000000000..6889ea715f
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/Project/ProjectUtils.cs
@@ -0,0 +1,17 @@
+using System;
+using System.IO;
+using Microsoft.Build.Construction;
+
+namespace GodotSharpTools.Project
+{
+ public static class ProjectUtils
+ {
+ public static void AddItemToProjectChecked(string projectPath, string itemType, string include)
+ {
+ var dir = Directory.GetParent(projectPath).FullName;
+ var root = ProjectRootElement.Open(projectPath);
+ if (root.AddItemChecked(itemType, include.RelativeToPath(dir).Replace("/", "\\")))
+ root.Save();
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs b/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..7115d8fc71
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("GodotSharpTools")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("ignacio")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/modules/mono/editor/GodotSharpTools/StringExtensions.cs b/modules/mono/editor/GodotSharpTools/StringExtensions.cs
new file mode 100644
index 0000000000..b66c86f8ce
--- /dev/null
+++ b/modules/mono/editor/GodotSharpTools/StringExtensions.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+namespace GodotSharpTools
+{
+ public static class StringExtensions
+ {
+ public static string RelativeToPath(this string path, string dir)
+ {
+ // Make sure the directory ends with a path separator
+ dir = Path.Combine(dir, " ").TrimEnd();
+
+ if (Path.DirectorySeparatorChar == '\\')
+ dir = dir.Replace("/", "\\") + "\\";
+
+ Uri fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute);
+ Uri relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute);
+
+ return relRoot.MakeRelativeUri(fullPath).ToString();
+ }
+
+ public static string NormalizePath(this string path)
+ {
+ bool rooted = path.IsAbsolutePath();
+
+ path = path.Replace('\\', '/');
+
+ string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
+
+ path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim();
+
+ return rooted ? Path.DirectorySeparatorChar.ToString() + path : path;
+ }
+
+ private static readonly string driveRoot = Path.GetPathRoot(Environment.CurrentDirectory);
+
+ public static bool IsAbsolutePath(this string path)
+ {
+ return path.StartsWith("/") || path.StartsWith("\\") || path.StartsWith(driveRoot);
+ }
+
+ public static string CsvEscape(this string value, char delimiter = ',')
+ {
+ bool hasSpecialChar = value.IndexOfAny(new char[] { '\"', '\n', '\r', delimiter }) != -1;
+
+ if (hasSpecialChar)
+ return "\"" + value.Replace("\"", "\"\"") + "\"";
+
+ return value;
+ }
+ }
+}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
new file mode 100644
index 0000000000..eb504ec021
--- /dev/null
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -0,0 +1,2158 @@
+/*************************************************************************/
+/* bindings_generator.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "bindings_generator.h"
+
+#ifdef DEBUG_METHODS_ENABLED
+
+#include "global_constants.h"
+#include "io/compression.h"
+#include "os/dir_access.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "project_settings.h"
+#include "ucaps.h"
+
+#include "../glue/cs_compressed.gen.h"
+#include "../godotsharp_defs.h"
+#include "../mono_gd/gd_mono_marshal.h"
+#include "../utils/path_utils.h"
+#include "../utils/string_utils.h"
+#include "csharp_project.h"
+#include "net_solution.h"
+
+#define CS_INDENT " "
+
+#define INDENT1 CS_INDENT
+#define INDENT2 INDENT1 INDENT1
+#define INDENT3 INDENT2 INDENT1
+#define INDENT4 INDENT3 INDENT1
+#define INDENT5 INDENT4 INDENT1
+
+#define MEMBER_BEGIN "\n" INDENT2
+
+#define OPEN_BLOCK "{\n"
+#define CLOSE_BLOCK "}\n"
+
+#define OPEN_BLOCK_L2 INDENT2 OPEN_BLOCK INDENT3
+#define OPEN_BLOCK_L3 INDENT3 OPEN_BLOCK INDENT4
+#define OPEN_BLOCK_L4 INDENT4 OPEN_BLOCK INDENT5
+#define CLOSE_BLOCK_L2 INDENT2 CLOSE_BLOCK
+#define CLOSE_BLOCK_L3 INDENT3 CLOSE_BLOCK
+#define CLOSE_BLOCK_L4 INDENT4 CLOSE_BLOCK
+
+#define LOCAL_RET "ret"
+
+#define CS_CLASS_NATIVECALLS "NativeCalls"
+#define CS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls"
+#define CS_FIELD_MEMORYOWN "memoryOwn"
+#define CS_PARAM_METHODBIND "method"
+#define CS_PARAM_INSTANCE "ptr"
+#define CS_SMETHOD_GETINSTANCE "GetPtr"
+#define CS_FIELD_SINGLETON "instance"
+#define CS_PROP_SINGLETON "Instance"
+#define CS_CLASS_SIGNALAWAITER "SignalAwaiter"
+#define CS_METHOD_CALL "Call"
+
+#define GLUE_HEADER_FILE "glue_header.h"
+#define ICALL_PREFIX "godot_icall_"
+#define SINGLETON_ICALL_SUFFIX "_get_singleton"
+#define ICALL_GET_METHODBIND ICALL_PREFIX "ClassDB_get_method"
+#define ICALL_CONNECT_SIGNAL_AWAITER ICALL_PREFIX "Object_connect_signal_awaiter"
+#define ICALL_OBJECT_DTOR ICALL_PREFIX "Object_Dtor"
+#define C_LOCAL_PTRCALL_ARGS "call_args"
+#define C_MACRO_OBJECT_CONSTRUCT "GODOTSHARP_INSTANCE_OBJECT"
+
+#define C_NS_MONOUTILS "GDMonoUtils"
+#define C_NS_MONOINTERNALS "GDMonoInternals"
+#define C_METHOD_TIE_MANAGED_TO_UNMANAGED C_NS_MONOINTERNALS "::tie_managed_to_unmanaged"
+#define C_METHOD_UNMANAGED_GET_MANAGED C_NS_MONOUTILS "::unmanaged_get_managed"
+
+#define C_NS_MONOMARSHAL "GDMonoMarshal"
+#define C_METHOD_MANAGED_TO_VARIANT C_NS_MONOMARSHAL "::mono_object_to_variant"
+#define C_METHOD_MANAGED_FROM_VARIANT C_NS_MONOMARSHAL "::variant_to_mono_object"
+#define C_METHOD_MONOSTR_TO_GODOT C_NS_MONOMARSHAL "::mono_string_to_godot"
+#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot"
+#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
+#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
+#define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary"
+#define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object"
+
+const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
+
+bool BindingsGenerator::verbose_output = false;
+
+static String snake_to_pascal_case(const String &p_identifier) {
+
+ String ret;
+ Vector<String> parts = p_identifier.split("_", true);
+
+ for (int i = 0; i < parts.size(); i++) {
+ String part = parts[i];
+
+ if (part.length()) {
+ part[0] = _find_upper(part[0]);
+ ret += part;
+ } else {
+ if (i == 0 || i == (parts.size() - 1)) {
+ // Preserve underscores at the beginning and end
+ ret += "_";
+ } else {
+ // Preserve contiguous underscores
+ if (parts[i - 1].length()) {
+ ret += "__";
+ } else {
+ ret += "_";
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+static String snake_to_camel_case(const String &p_identifier) {
+
+ String ret;
+ Vector<String> parts = p_identifier.split("_", true);
+
+ for (int i = 0; i < parts.size(); i++) {
+ String part = parts[i];
+
+ if (part.length()) {
+ if (i != 0)
+ part[0] = _find_upper(part[0]);
+ ret += part;
+ } else {
+ if (i == 0 || i == (parts.size() - 1)) {
+ // Preserve underscores at the beginning and end
+ ret += "_";
+ } else {
+ // Preserve contiguous underscores
+ if (parts[i - 1].length()) {
+ ret += "__";
+ } else {
+ ret += "_";
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+void BindingsGenerator::_generate_header_icalls() {
+
+ core_custom_icalls.clear();
+
+ core_custom_icalls.push_back(InternalCall(ICALL_GET_METHODBIND, "IntPtr", "string type, string method"));
+ core_custom_icalls.push_back(InternalCall(ICALL_OBJECT_DTOR, "void", "IntPtr ptr"));
+
+ core_custom_icalls.push_back(InternalCall(ICALL_CONNECT_SIGNAL_AWAITER, "Error",
+ "IntPtr source, string signal, IntPtr target, " CS_CLASS_SIGNALAWAITER " awaiter"));
+
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "NodePath_Ctor", "IntPtr", "string path"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "NodePath_Dtor", "void", "IntPtr ptr"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "NodePath_operator_String", "string", "IntPtr ptr"));
+
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "RID_Ctor", "IntPtr", "IntPtr from"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "RID_Dtor", "void", "IntPtr ptr"));
+
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_md5_buffer", "byte[]", "string str"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_md5_text", "string", "string str"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_rfind", "int", "string str, string what, int from"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_rfindn", "int", "string str, string what, int from"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_sha256_buffer", "byte[]", "string str"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "String_sha256_text", "string", "string str"));
+
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_bytes2var", "object", "byte[] bytes"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_convert", "object", "object what, int type"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_hash", "int", "object var"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_instance_from_id", "Object", "int instance_id"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_print", "void", "object[] what"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_printerr", "void", "object[] what"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_printraw", "void", "object[] what"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_prints", "void", "object[] what"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_printt", "void", "object[] what"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_seed", "void", "int seed"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_str", "string", "object[] what"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_str2var", "object", "string str"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_type_exists", "bool", "string type"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_var2bytes", "byte[]", "object what"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_var2str", "string", "object var"));
+ core_custom_icalls.push_back(InternalCall(ICALL_PREFIX "Godot_weakref", "WeakRef", "IntPtr obj"));
+}
+
+void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
+
+ for (const List<MethodInterface>::Element *E = p_itype.methods.front(); E; E = E->next()) {
+ const MethodInterface &imethod = E->get();
+
+ if (imethod.is_virtual)
+ continue;
+
+ const TypeInterface *return_type = _get_type_by_name_or_placeholder(imethod.return_type);
+
+ String im_sig = "IntPtr " CS_PARAM_METHODBIND ", IntPtr " CS_PARAM_INSTANCE;
+ String im_unique_sig = imethod.return_type + ",IntPtr,IntPtr";
+
+ // Get arguments information
+ int i = 0;
+ for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) {
+ const TypeInterface *arg_type = _get_type_by_name_or_placeholder(F->get().type);
+
+ im_sig += ", ";
+ im_sig += arg_type->im_type_in;
+ im_sig += " arg";
+ im_sig += itos(i + 1);
+
+ im_unique_sig += ",";
+ im_unique_sig += get_unique_sig(*arg_type);
+
+ i++;
+ }
+
+ // godot_icall_{argc}_{icallcount}
+ String icall_method = ICALL_PREFIX + itos(imethod.arguments.size()) + "_" + itos(method_icalls.size());
+
+ InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, return_type->im_type_out, im_sig, im_unique_sig);
+
+ List<InternalCall>::Element *match = method_icalls.find(im_icall);
+
+ if (match) {
+ if (p_itype.api_type != ClassDB::API_EDITOR)
+ match->get().editor_only = false;
+ method_icalls_map.insert(&E->get(), &match->get());
+ } else {
+ List<InternalCall>::Element *added = method_icalls.push_back(im_icall);
+ method_icalls_map.insert(&E->get(), &added->get());
+ }
+ }
+}
+
+Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bool p_verbose_output) {
+
+ verbose_output = p_verbose_output;
+
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+
+ if (!DirAccess::exists(p_output_dir)) {
+ Error err = da->make_dir_recursive(p_output_dir);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+ }
+
+ da->change_dir(p_output_dir);
+ da->make_dir("Core");
+ da->make_dir("ObjectType");
+
+ String core_dir = path_join(p_output_dir, "Core");
+ String obj_type_dir = path_join(p_output_dir, "ObjectType");
+
+ Vector<String> compile_items;
+
+ NETSolution solution(API_ASSEMBLY_NAME);
+
+ if (!solution.set_path(p_output_dir))
+ return ERR_FILE_NOT_FOUND;
+
+ for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) {
+ const TypeInterface &itype = E->get();
+
+ if (itype.api_type == ClassDB::API_EDITOR)
+ continue;
+
+ String output_file = path_join(obj_type_dir, E->get().proxy_name + ".cs");
+ Error err = _generate_cs_type(E->get(), output_file);
+
+ if (err == ERR_SKIP)
+ continue;
+
+ if (err != OK)
+ return err;
+
+ compile_items.push_back(output_file);
+ }
+
+#define GENERATE_BUILTIN_TYPE(m_name) \
+ { \
+ String output_file = path_join(core_dir, #m_name ".cs"); \
+ Error err = _generate_cs_type(builtin_types[#m_name], output_file); \
+ if (err != OK) \
+ return err; \
+ compile_items.push_back(output_file); \
+ }
+
+ GENERATE_BUILTIN_TYPE(NodePath);
+ GENERATE_BUILTIN_TYPE(RID);
+
+#undef GENERATE_BUILTIN_TYPE
+
+ // Generate source for GlobalConstants
+
+ String constants_source;
+ int global_constants_count = GlobalConstants::get_global_constant_count();
+
+ if (global_constants_count > 0) {
+ Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@Global Scope");
+
+ ERR_EXPLAIN("Could not find `@Global Scope` in DocData");
+ ERR_FAIL_COND_V(!match, ERR_BUG);
+
+ const DocData::ClassDoc &global_scope_doc = match->value();
+
+ for (int i = 0; i < global_constants_count; i++) {
+ const DocData::ConstantDoc &const_doc = global_scope_doc.constants[i];
+
+ if (i > 0)
+ constants_source += MEMBER_BEGIN;
+
+ if (const_doc.description.size()) {
+ constants_source += "/// <summary>\n";
+
+ Vector<String> description_lines = const_doc.description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ if (description_lines[i].size()) {
+ constants_source += INDENT2 "/// ";
+ constants_source += description_lines[i].strip_edges().xml_escape();
+ constants_source += "\n";
+ }
+ }
+
+ constants_source += INDENT2 "/// </summary>" MEMBER_BEGIN;
+ }
+
+ constants_source += "public const int ";
+ constants_source += GlobalConstants::get_global_constant_name(i);
+ constants_source += " = ";
+ constants_source += itos(GlobalConstants::get_global_constant_value(i));
+ constants_source += ";";
+ }
+ }
+
+ // Generate sources from compressed files
+
+ Map<String, CompressedFile> compressed_files;
+ get_compressed_files(compressed_files);
+
+ for (Map<String, CompressedFile>::Element *E = compressed_files.front(); E; E = E->next()) {
+ const String &file_name = E->key();
+ const CompressedFile &file_data = E->value();
+
+ String output_file = path_join(core_dir, file_name);
+
+ Vector<uint8_t> data;
+ data.resize(file_data.uncompressed_size);
+ Compression::decompress(data.ptr(), file_data.uncompressed_size, file_data.data, file_data.compressed_size, Compression::MODE_DEFLATE);
+
+ if (file_name.get_basename() == BINDINGS_GLOBAL_SCOPE_CLASS) {
+ // GD.cs must be formatted to include the generated global constants
+ String data_str = String::utf8(reinterpret_cast<const char *>(data.ptr()), data.size());
+
+ Dictionary format_keys;
+ format_keys["GodotGlobalConstants"] = constants_source;
+ data_str = data_str.format(format_keys, "/*{_}*/");
+
+ CharString data_utf8 = data_str.utf8();
+ data.resize(data_utf8.length());
+ copymem(data.ptr(), reinterpret_cast<const uint8_t *>(data_utf8.get_data()), data_utf8.length());
+ }
+
+ FileAccessRef file = FileAccess::open(output_file, FileAccess::WRITE);
+ ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
+ file->store_buffer(data.ptr(), data.size());
+ file->close();
+
+ compile_items.push_back(output_file);
+ }
+
+ List<String> cs_icalls_content;
+
+ cs_icalls_content.push_back("using System;\n"
+ "using System.Runtime.CompilerServices;\n"
+ "using System.Collections.Generic;\n"
+ "\n");
+ cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS "\n" INDENT1 OPEN_BLOCK);
+
+#define ADD_INTERNAL_CALL(m_icall) \
+ if (!m_icall.editor_only) { \
+ cs_icalls_content.push_back(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
+ cs_icalls_content.push_back(INDENT2 "internal extern static "); \
+ cs_icalls_content.push_back(m_icall.im_type_out + " "); \
+ cs_icalls_content.push_back(m_icall.name + "("); \
+ cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
+ }
+
+ for (const List<InternalCall>::Element *E = core_custom_icalls.front(); E; E = E->next())
+ ADD_INTERNAL_CALL(E->get());
+ for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next())
+ ADD_INTERNAL_CALL(E->get());
+
+#undef ADD_INTERNAL_CALL
+
+ cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
+
+ String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS ".cs");
+
+ Error err = _save_file(internal_methods_file, cs_icalls_content);
+ if (err != OK)
+ return err;
+
+ compile_items.push_back(internal_methods_file);
+
+ String guid = CSharpProject::generate_core_api_project(p_output_dir, compile_items);
+
+ solution.add_new_project(API_ASSEMBLY_NAME, guid);
+
+ Error sln_error = solution.save();
+ if (sln_error != OK) {
+ ERR_PRINT("Could not to save .NET solution.");
+ return sln_error;
+ }
+
+ if (verbose_output)
+ OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n");
+
+ return OK;
+}
+
+Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output) {
+
+ verbose_output = p_verbose_output;
+
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+
+ if (!DirAccess::exists(p_output_dir)) {
+ Error err = da->make_dir_recursive(p_output_dir);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+ }
+
+ da->change_dir(p_output_dir);
+ da->make_dir("Core");
+ da->make_dir("ObjectType");
+
+ String core_dir = path_join(p_output_dir, "Core");
+ String obj_type_dir = path_join(p_output_dir, "ObjectType");
+
+ Vector<String> compile_items;
+
+ NETSolution solution(EDITOR_API_ASSEMBLY_NAME);
+
+ if (!solution.set_path(p_output_dir))
+ return ERR_FILE_NOT_FOUND;
+
+ for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next()) {
+ const TypeInterface &itype = E->get();
+
+ if (itype.api_type != ClassDB::API_EDITOR)
+ continue;
+
+ String output_file = path_join(obj_type_dir, E->get().proxy_name + ".cs");
+ Error err = _generate_cs_type(E->get(), output_file);
+
+ if (err == ERR_SKIP)
+ continue;
+
+ if (err != OK)
+ return err;
+
+ compile_items.push_back(output_file);
+ }
+
+ List<String> cs_icalls_content;
+
+ cs_icalls_content.push_back("using System;\n"
+ "using System.Runtime.CompilerServices;\n"
+ "using System.Collections.Generic;\n"
+ "\n");
+ cs_icalls_content.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ cs_icalls_content.push_back(INDENT1 "internal static class " CS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
+
+#define ADD_INTERNAL_CALL(m_icall) \
+ if (m_icall.editor_only) { \
+ cs_icalls_content.push_back(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
+ cs_icalls_content.push_back(INDENT2 "internal extern static "); \
+ cs_icalls_content.push_back(m_icall.im_type_out + " "); \
+ cs_icalls_content.push_back(m_icall.name + "("); \
+ cs_icalls_content.push_back(m_icall.im_sig + ");\n"); \
+ }
+
+ for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next())
+ ADD_INTERNAL_CALL(E->get());
+ for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next())
+ ADD_INTERNAL_CALL(E->get());
+
+#undef ADD_INTERNAL_CALL
+
+ cs_icalls_content.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
+
+ String internal_methods_file = path_join(core_dir, CS_CLASS_NATIVECALLS_EDITOR ".cs");
+
+ Error err = _save_file(internal_methods_file, cs_icalls_content);
+ if (err != OK)
+ return err;
+
+ compile_items.push_back(internal_methods_file);
+
+ String guid = CSharpProject::generate_editor_api_project(p_output_dir, p_core_dll_path, compile_items);
+
+ solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, guid);
+
+ Error sln_error = solution.save();
+ if (sln_error != OK) {
+ ERR_PRINT("Could not to save .NET solution.");
+ return sln_error;
+ }
+
+ if (verbose_output)
+ OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n");
+
+ return OK;
+}
+
+// TODO: there are constants that hide inherited members. must explicitly use `new` to avoid warnings
+// e.g.: warning CS0108: 'SpriteBase3D.FLAG_MAX' hides inherited member 'GeometryInstance.FLAG_MAX'. Use the new keyword if hiding was intended.
+Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const String &p_output_file) {
+
+ bool is_derived_type = itype.base_name.length();
+
+ List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
+
+ if (verbose_output)
+ OS::get_singleton()->print(String("Generating " + itype.proxy_name + ".cs...\n").utf8());
+
+ String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor");
+
+ List<String> output;
+
+ output.push_back("using System;\n"); // IntPtr
+
+ if (itype.requires_collections)
+ output.push_back("using System.Collections.Generic;\n"); // Dictionary
+
+ output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+
+ const DocData::ClassDoc *class_doc = itype.class_doc;
+
+ if (class_doc && class_doc->description.size()) {
+ output.push_back(INDENT1 "/// <summary>\n");
+
+ Vector<String> description_lines = class_doc->description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ if (description_lines[i].size()) {
+ output.push_back(INDENT1 "/// ");
+ output.push_back(description_lines[i].strip_edges().xml_escape());
+ output.push_back("\n");
+ }
+ }
+
+ output.push_back(INDENT1 "/// </summary>\n");
+ }
+
+ output.push_back(INDENT1 "public ");
+ output.push_back(itype.is_singleton ? "static class " : "class ");
+ output.push_back(itype.proxy_name);
+
+ if (itype.is_singleton || !itype.is_object_type) {
+ output.push_back("\n");
+ } else if (!is_derived_type) {
+ output.push_back(" : IDisposable\n");
+ } else if (obj_types.has(itype.base_name)) {
+ output.push_back(" : ");
+ output.push_back(obj_types[itype.base_name].proxy_name);
+ output.push_back("\n");
+ } else {
+ ERR_PRINTS("Base type '" + itype.base_name + "' does not exist, for class " + itype.name);
+ return ERR_INVALID_DATA;
+ }
+
+ output.push_back(INDENT1 "{");
+
+ if (class_doc) {
+
+ // Add constants
+
+ for (int i = 0; i < class_doc->constants.size(); i++) {
+ const DocData::ConstantDoc &const_doc = class_doc->constants[i];
+
+ if (const_doc.description.size()) {
+ output.push_back(MEMBER_BEGIN "/// <summary>\n");
+
+ Vector<String> description_lines = const_doc.description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ if (description_lines[i].size()) {
+ output.push_back(INDENT2 "/// ");
+ output.push_back(description_lines[i].strip_edges().xml_escape());
+ output.push_back("\n");
+ }
+ }
+
+ output.push_back(INDENT2 "/// </summary>");
+ }
+
+ output.push_back(MEMBER_BEGIN "public const int ");
+ output.push_back(const_doc.name);
+ output.push_back(" = ");
+ output.push_back(const_doc.value);
+ output.push_back(";");
+ }
+
+ if (class_doc->constants.size())
+ output.push_back("\n");
+
+ // Add properties
+
+ const Vector<DocData::PropertyDoc> &properties = class_doc->properties;
+
+ for (int i = 0; i < properties.size(); i++) {
+ const DocData::PropertyDoc &prop_doc = properties[i];
+ Error prop_err = _generate_cs_property(itype, prop_doc, output);
+ if (prop_err != OK) {
+ ERR_EXPLAIN("Failed to generate property '" + prop_doc.name + "' for class '" + itype.name + "'");
+ ERR_FAIL_V(prop_err);
+ }
+ }
+
+ if (class_doc->properties.size())
+ output.push_back("\n");
+ }
+
+ if (!itype.is_object_type) {
+ output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"" + itype.name + "\";\n");
+ output.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
+ output.push_back(MEMBER_BEGIN "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
+
+ output.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(");
+ output.push_back(itype.proxy_name);
+ output.push_back(" instance)\n" OPEN_BLOCK_L2 "return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
+
+ // Add Destructor
+ output.push_back(MEMBER_BEGIN "~");
+ output.push_back(itype.proxy_name);
+ output.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
+
+ // Add the Dispose from IDisposable
+ output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
+
+ // Add the virtual Dispose
+ output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
+ "if (disposed) return;\n" INDENT3
+ "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3 "NativeCalls.godot_icall_");
+ output.push_back(itype.proxy_name);
+ output.push_back("_Dtor(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L3 INDENT3
+ "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
+
+ output.push_back(MEMBER_BEGIN "internal ");
+ output.push_back(itype.proxy_name);
+ output.push_back("(IntPtr " BINDINGS_PTR_FIELD ")\n" OPEN_BLOCK_L2 "this." BINDINGS_PTR_FIELD " = " BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
+
+ output.push_back(MEMBER_BEGIN "public IntPtr NativeInstance\n" OPEN_BLOCK_L2
+ "get { return " BINDINGS_PTR_FIELD "; }\n" CLOSE_BLOCK_L2);
+ } else if (itype.is_singleton) {
+ // Add the type name and the singleton pointer as static fields
+
+ output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.push_back(itype.name);
+ output.push_back("\";\n");
+
+ output.push_back(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
+ output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
+ output.push_back("." ICALL_PREFIX);
+ output.push_back(itype.name);
+ output.push_back(SINGLETON_ICALL_SUFFIX "();\n");
+ } else {
+ // Add member fields
+
+ output.push_back(MEMBER_BEGIN "private const string " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.push_back(itype.name);
+ output.push_back("\";\n");
+
+ // Only the base class stores the pointer to the native object
+ // This pointer is expected to be and must be of type Object*
+ if (!is_derived_type) {
+ output.push_back(MEMBER_BEGIN "private bool disposed = false;\n");
+ output.push_back(INDENT2 "internal IntPtr " BINDINGS_PTR_FIELD ";\n");
+ output.push_back(INDENT2 "internal bool " CS_FIELD_MEMORYOWN ";\n");
+ }
+
+ // Add default constructor
+ if (itype.is_instantiable) {
+ output.push_back(MEMBER_BEGIN "public ");
+ output.push_back(itype.proxy_name);
+ output.push_back("() : this(");
+ output.push_back(itype.memory_own ? "true" : "false");
+
+ // The default constructor may also be called by the engine when instancing existing native objects
+ // The engine will initialize the pointer field of the managed side before calling the constructor
+ // This is why we only allocate a new native object from the constructor if the pointer field is not set
+ output.push_back(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
+ output.push_back(itype.api_type == ClassDB::API_EDITOR ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS);
+ output.push_back("." + ctor_method);
+ output.push_back("(this);\n" CLOSE_BLOCK_L2);
+ } else {
+ // Hide the constructor
+ output.push_back(MEMBER_BEGIN "internal ");
+ output.push_back(itype.proxy_name);
+ output.push_back("() {}\n");
+ }
+
+ // Add.. em.. trick constructor. Sort of.
+ output.push_back(MEMBER_BEGIN "internal ");
+ output.push_back(itype.proxy_name);
+ if (is_derived_type) {
+ output.push_back("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
+ } else {
+ output.push_back("(bool " CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L2
+ "this." CS_FIELD_MEMORYOWN " = " CS_FIELD_MEMORYOWN ";\n" CLOSE_BLOCK_L2);
+ }
+
+ // Add methods
+
+ if (!is_derived_type) {
+ output.push_back(MEMBER_BEGIN "public IntPtr NativeInstance\n" OPEN_BLOCK_L2
+ "get { return " BINDINGS_PTR_FIELD "; }\n" CLOSE_BLOCK_L2);
+
+ output.push_back(MEMBER_BEGIN "internal static IntPtr " CS_SMETHOD_GETINSTANCE "(Object instance)\n" OPEN_BLOCK_L2
+ "return instance == null ? IntPtr.Zero : instance." BINDINGS_PTR_FIELD ";\n" CLOSE_BLOCK_L2);
+ }
+
+ if (!is_derived_type) {
+ // Add destructor
+ output.push_back(MEMBER_BEGIN "~");
+ output.push_back(itype.proxy_name);
+ output.push_back("()\n" OPEN_BLOCK_L2 "Dispose(false);\n" CLOSE_BLOCK_L2);
+
+ // Add the Dispose from IDisposable
+ output.push_back(MEMBER_BEGIN "public void Dispose()\n" OPEN_BLOCK_L2 "Dispose(true);\n" INDENT3 "GC.SuppressFinalize(this);\n" CLOSE_BLOCK_L2);
+
+ // Add the virtual Dispose
+ output.push_back(MEMBER_BEGIN "public virtual void Dispose(bool disposing)\n" OPEN_BLOCK_L2
+ "if (disposed) return;\n" INDENT3
+ "if (" BINDINGS_PTR_FIELD " != IntPtr.Zero)\n" OPEN_BLOCK_L3
+ "if (" CS_FIELD_MEMORYOWN ")\n" OPEN_BLOCK_L4 CS_FIELD_MEMORYOWN
+ " = false;\n" INDENT5 CS_CLASS_NATIVECALLS "." ICALL_OBJECT_DTOR
+ "(" BINDINGS_PTR_FIELD ");\n" INDENT5 BINDINGS_PTR_FIELD
+ " = IntPtr.Zero;\n" CLOSE_BLOCK_L4 CLOSE_BLOCK_L3 INDENT3
+ "GC.SuppressFinalize(this);\n" INDENT3 "disposed = true;\n" CLOSE_BLOCK_L2);
+
+ Map<String, TypeInterface>::Element *array_itype = builtin_types.find("Array");
+
+ if (!array_itype) {
+ ERR_PRINT("BUG: Array type interface not found!");
+ return ERR_BUG;
+ }
+
+ Map<String, TypeInterface>::Element *object_itype = obj_types.find("Object");
+
+ if (!object_itype) {
+ ERR_PRINT("BUG: Object type interface not found!");
+ return ERR_BUG;
+ }
+
+ output.push_back(MEMBER_BEGIN "public " CS_CLASS_SIGNALAWAITER " ToSignal(");
+ output.push_back(object_itype->get().cs_type);
+ output.push_back(" source, string signal)\n" OPEN_BLOCK_L2
+ "return new " CS_CLASS_SIGNALAWAITER "(source, signal, this);\n" CLOSE_BLOCK_L2);
+ }
+ }
+
+ Map<String, String>::Element *extra_member = extra_members.find(itype.name);
+ if (extra_member)
+ output.push_back(extra_member->get());
+
+ int method_bind_count = 0;
+ for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
+ const MethodInterface &imethod = E->get();
+ Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output);
+ if (method_err != OK) {
+ ERR_EXPLAIN("Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'");
+ ERR_FAIL_V(method_err);
+ }
+ }
+
+ if (itype.is_singleton) {
+ InternalCall singleton_icall = InternalCall(itype.api_type, ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX, "IntPtr");
+
+ if (!find_icall_by_name(singleton_icall.name, custom_icalls))
+ custom_icalls.push_back(singleton_icall);
+ }
+
+ if (itype.is_instantiable) {
+ InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
+
+ if (!find_icall_by_name(ctor_icall.name, custom_icalls))
+ custom_icalls.push_back(ctor_icall);
+ }
+
+ output.push_back(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
+
+ return _save_file(p_output_file, output);
+}
+
+Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output) {
+
+ const MethodInterface *setter = p_itype.find_method_by_name(p_prop_doc.setter);
+
+ // Search it in base types too
+ const TypeInterface *current_type = &p_itype;
+ while (!setter && current_type->base_name.length()) {
+ Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
+ ERR_FAIL_NULL_V(base_match, ERR_BUG);
+ current_type = &base_match->get();
+ setter = current_type->find_method_by_name(p_prop_doc.setter);
+ }
+
+ const MethodInterface *getter = p_itype.find_method_by_name(p_prop_doc.getter);
+
+ // Search it in base types too
+ current_type = &p_itype;
+ while (!getter && current_type->base_name.length()) {
+ Map<String, TypeInterface>::Element *base_match = obj_types.find(current_type->base_name);
+ ERR_FAIL_NULL_V(base_match, ERR_BUG);
+ current_type = &base_match->get();
+ getter = current_type->find_method_by_name(p_prop_doc.getter);
+ }
+
+ ERR_FAIL_COND_V(!setter && !getter, ERR_BUG);
+
+ bool is_valid = false;
+ int prop_index = ClassDB::get_property_index(p_itype.name, p_prop_doc.name, &is_valid);
+ ERR_FAIL_COND_V(!is_valid, ERR_BUG);
+
+ if (setter) {
+ int setter_argc = prop_index != -1 ? 2 : 1;
+ ERR_FAIL_COND_V(setter->arguments.size() != setter_argc, ERR_BUG);
+ }
+
+ if (getter) {
+ int getter_argc = prop_index != -1 ? 1 : 0;
+ ERR_FAIL_COND_V(getter->arguments.size() != getter_argc, ERR_BUG);
+ }
+
+ if (getter && setter) {
+ ERR_FAIL_COND_V(getter->return_type != setter->arguments.back()->get().type, ERR_BUG);
+ }
+
+ // Let's not trust PropertyDoc::type
+ String proptype_name = getter ? getter->return_type : setter->arguments.back()->get().type;
+
+ const TypeInterface *prop_itype = _get_type_by_name_or_null(proptype_name);
+ if (!prop_itype) {
+ // Try with underscore prefix
+ prop_itype = _get_type_by_name_or_null("_" + proptype_name);
+ }
+
+ ERR_FAIL_NULL_V(prop_itype, ERR_BUG);
+
+ String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_prop_doc.name));
+
+ // Prevent property and enclosing type from sharing the same name
+ if (prop_proxy_name == p_itype.proxy_name) {
+ if (verbose_output) {
+ WARN_PRINTS("Name of property `" + prop_proxy_name + "` is ambiguous with the name of its class `" +
+ p_itype.proxy_name + "`. Renaming property to `" + prop_proxy_name + "_`");
+ }
+
+ prop_proxy_name += "_";
+ }
+
+ if (p_prop_doc.description.size()) {
+ p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
+
+ Vector<String> description_lines = p_prop_doc.description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ if (description_lines[i].size()) {
+ p_output.push_back(INDENT2 "/// ");
+ p_output.push_back(description_lines[i].strip_edges().xml_escape());
+ p_output.push_back("\n");
+ }
+ }
+
+ p_output.push_back(INDENT2 "/// </summary>");
+ }
+
+ p_output.push_back(MEMBER_BEGIN "public ");
+
+ if (p_itype.is_singleton)
+ p_output.push_back("static ");
+
+ p_output.push_back(prop_itype->cs_type);
+ p_output.push_back(" ");
+ p_output.push_back(prop_proxy_name.replace("/", "__"));
+ p_output.push_back("\n" INDENT2 OPEN_BLOCK);
+
+ if (getter) {
+ p_output.push_back(INDENT3 "get\n" OPEN_BLOCK_L3);
+ p_output.push_back("return ");
+ p_output.push_back(getter->proxy_name + "(");
+ if (prop_index != -1)
+ p_output.push_back(itos(prop_index));
+ p_output.push_back(");\n" CLOSE_BLOCK_L3);
+ }
+
+ if (setter) {
+ p_output.push_back(INDENT3 "set\n" OPEN_BLOCK_L3);
+ p_output.push_back(setter->proxy_name + "(");
+ if (prop_index != -1)
+ p_output.push_back(itos(prop_index) + ", ");
+ p_output.push_back("value);\n" CLOSE_BLOCK_L3);
+ }
+
+ p_output.push_back(CLOSE_BLOCK_L2);
+
+ return OK;
+}
+
+Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output) {
+
+ const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type);
+
+ String method_bind_field = "method_bind_" + itos(p_method_bind_count);
+
+ String icall_params = method_bind_field + ", " + sformat(p_itype.cs_in, "this");
+ String arguments_sig;
+ String cs_in_statements;
+
+ List<String> default_args_doc;
+
+ // Retrieve information from the arguments
+ for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
+ const ArgumentInterface &iarg = F->get();
+ const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
+
+ // Add the current arguments to the signature
+ // If the argument has a default value which is not a constant, we will make it Nullable
+ {
+ if (F != p_imethod.arguments.front())
+ arguments_sig += ", ";
+
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ arguments_sig += "Nullable<";
+
+ arguments_sig += arg_type->cs_type;
+
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ arguments_sig += "> ";
+ else
+ arguments_sig += " ";
+
+ arguments_sig += iarg.name;
+
+ if (iarg.default_argument.size()) {
+ if (iarg.def_param_mode != ArgumentInterface::CONSTANT)
+ arguments_sig += " = null";
+ else
+ arguments_sig += " = " + sformat(iarg.default_argument, arg_type->cs_type);
+ }
+ }
+
+ icall_params += ", ";
+
+ if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) {
+ // The default value of an argument must be constant. Otherwise we make it Nullable and do the following:
+ // Type arg_in = arg.HasValue ? arg.Value : <non-const default value>;
+ String arg_in = iarg.name;
+ arg_in += "_in";
+
+ cs_in_statements += arg_type->cs_type;
+ cs_in_statements += " ";
+ cs_in_statements += arg_in;
+ cs_in_statements += " = ";
+ cs_in_statements += iarg.name;
+
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ cs_in_statements += ".HasValue ? ";
+ else
+ cs_in_statements += " != null ? ";
+
+ cs_in_statements += iarg.name;
+
+ if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL)
+ cs_in_statements += ".Value : ";
+ else
+ cs_in_statements += " : ";
+
+ String def_arg = sformat(iarg.default_argument, arg_type->cs_type);
+
+ 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);
+
+ default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param is null, then the default value is " + def_arg + "</param>\n");
+ } else {
+ icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
+ }
+ }
+
+ // Generate method
+ {
+ if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
+ p_output.push_back(MEMBER_BEGIN "private ");
+ p_output.push_back(p_itype.is_singleton ? "static IntPtr " : "IntPtr ");
+ p_output.push_back(method_bind_field + " = " CS_CLASS_NATIVECALLS "." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
+ p_output.push_back(p_imethod.name);
+ p_output.push_back("\");\n");
+ }
+
+ if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
+ p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
+
+ Vector<String> description_lines = p_imethod.method_doc->description.split("\n");
+
+ for (int i = 0; i < description_lines.size(); i++) {
+ if (description_lines[i].size()) {
+ p_output.push_back(INDENT2 "/// ");
+ p_output.push_back(description_lines[i].strip_edges().xml_escape());
+ p_output.push_back("\n");
+ }
+ }
+
+ for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
+ p_output.push_back(E->get().xml_escape());
+ }
+
+ p_output.push_back(INDENT2 "/// </summary>");
+ }
+
+ if (!p_imethod.is_internal) {
+ p_output.push_back(MEMBER_BEGIN "[GodotMethod(\"");
+ p_output.push_back(p_imethod.name);
+ p_output.push_back("\")]");
+ }
+
+ p_output.push_back(MEMBER_BEGIN);
+ p_output.push_back(p_imethod.is_internal ? "internal " : "public ");
+
+ if (p_itype.is_singleton) {
+ p_output.push_back("static ");
+ } else if (p_imethod.is_virtual) {
+ p_output.push_back("virtual ");
+ }
+
+ p_output.push_back(return_type->cs_type + " ");
+ p_output.push_back(p_imethod.proxy_name + "(");
+ p_output.push_back(arguments_sig + ")\n" OPEN_BLOCK_L2);
+
+ if (p_imethod.is_virtual) {
+ // Godot virtual method must be overridden, therefore we return a default value by default.
+
+ if (return_type->name == "void") {
+ p_output.push_back("return;\n" CLOSE_BLOCK_L2);
+ } else {
+ p_output.push_back("return default(");
+ p_output.push_back(return_type->cs_type);
+ p_output.push_back(");\n" CLOSE_BLOCK_L2);
+ }
+
+ return OK; // Won't increment method bind count
+ }
+
+ if (p_imethod.requires_object_call) {
+ // Fallback to Godot's object.Call(string, params)
+
+ p_output.push_back(CS_METHOD_CALL "(\"");
+ p_output.push_back(p_imethod.name);
+ p_output.push_back("\"");
+
+ for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
+ p_output.push_back(", ");
+ p_output.push_back(F->get().name);
+ }
+
+ p_output.push_back(");\n" CLOSE_BLOCK_L2);
+
+ return OK; // Won't increment method bind count
+ }
+
+ const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ ERR_FAIL_NULL_V(match, ERR_BUG);
+
+ const InternalCall *im_icall = match->value();
+
+ String im_call = im_icall->editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS;
+ im_call += "." + im_icall->name + "(" + icall_params + ");\n";
+
+ if (p_imethod.arguments.size())
+ p_output.push_back(cs_in_statements);
+
+ if (return_type->name == "void") {
+ p_output.push_back(im_call);
+ } else if (return_type->cs_out.empty()) {
+ p_output.push_back("return " + im_call);
+ } else {
+ p_output.push_back(return_type->im_type_out);
+ p_output.push_back(" " LOCAL_RET " = ");
+ p_output.push_back(im_call);
+ p_output.push_back(INDENT3);
+ p_output.push_back(sformat(return_type->cs_out, LOCAL_RET) + "\n");
+ }
+
+ p_output.push_back(CLOSE_BLOCK_L2);
+ }
+
+ p_method_bind_count++;
+ return OK;
+}
+
+Error BindingsGenerator::generate_glue(const String &p_output_dir) {
+
+ verbose_output = true;
+
+ bool dir_exists = DirAccess::exists(p_output_dir);
+ ERR_EXPLAIN("The output directory does not exist.");
+ ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
+
+ List<String> output;
+
+ output.push_back("#include \"" GLUE_HEADER_FILE "\"\n"
+ "\n");
+
+ generated_icall_funcs.clear();
+
+ for (Map<String, TypeInterface>::Element *type_elem = obj_types.front(); type_elem; type_elem = type_elem->next()) {
+ const TypeInterface &itype = type_elem->get();
+
+ List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
+
+ OS::get_singleton()->print(String("Generating " + itype.name + "...\n").utf8());
+
+ String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor");
+
+ for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
+ const MethodInterface &imethod = E->get();
+ Error method_err = _generate_glue_method(itype, imethod, output);
+ if (method_err != OK) {
+ ERR_EXPLAIN("Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'");
+ ERR_FAIL_V(method_err);
+ }
+ }
+
+ if (itype.is_singleton) {
+ String singleton_icall_name = ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX;
+ InternalCall singleton_icall = InternalCall(itype.api_type, singleton_icall_name, "IntPtr");
+
+ if (!find_icall_by_name(singleton_icall.name, custom_icalls))
+ custom_icalls.push_back(singleton_icall);
+
+ output.push_back("Object* ");
+ output.push_back(singleton_icall_name);
+ output.push_back("() " OPEN_BLOCK "\treturn ProjectSettings::get_singleton()->get_singleton_object(\"");
+ output.push_back(itype.proxy_name);
+ output.push_back("\");\n" CLOSE_BLOCK "\n");
+ }
+
+ if (itype.is_instantiable) {
+ InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
+
+ if (!find_icall_by_name(ctor_icall.name, custom_icalls))
+ custom_icalls.push_back(ctor_icall);
+
+ output.push_back("Object* ");
+ output.push_back(ctor_method);
+ output.push_back("(MonoObject* obj) " OPEN_BLOCK
+ "\t" C_MACRO_OBJECT_CONSTRUCT "(instance, \"");
+ output.push_back(itype.name);
+ output.push_back("\");\n"
+ "\t" C_METHOD_TIE_MANAGED_TO_UNMANAGED "(obj, instance);\n"
+ "\treturn instance;\n" CLOSE_BLOCK "\n");
+ }
+ }
+
+ output.push_back("namespace GodotSharpBindings\n" OPEN_BLOCK);
+ output.push_back("uint64_t get_core_api_hash() { return ");
+ output.push_back(itos(GDMono::get_singleton()->get_api_core_hash()) + "; }\n");
+ output.push_back("#ifdef TOOLS_ENABLED\n"
+ "uint64_t get_editor_api_hash() { return ");
+ output.push_back(itos(GDMono::get_singleton()->get_api_editor_hash()) +
+ "; }\n#endif // TOOLS_ENABLED\n");
+ output.push_back("void register_generated_icalls() " OPEN_BLOCK);
+
+#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
+ { \
+ output.push_back("\tmono_add_internal_call("); \
+ output.push_back("\"" BINDINGS_NAMESPACE "."); \
+ output.push_back(m_icall.editor_only ? CS_CLASS_NATIVECALLS_EDITOR : CS_CLASS_NATIVECALLS); \
+ output.push_back("::"); \
+ output.push_back(m_icall.name); \
+ output.push_back("\", (void*)"); \
+ output.push_back(m_icall.name); \
+ output.push_back(");\n"); \
+ }
+
+ bool tools_sequence = false;
+ for (const List<InternalCall>::Element *E = core_custom_icalls.front(); E; E = E->next()) {
+
+ if (tools_sequence) {
+ if (!E->get().editor_only) {
+ tools_sequence = false;
+ output.push_back("#endif\n");
+ }
+ } else {
+ if (E->get().editor_only) {
+ output.push_back("#ifdef TOOLS_ENABLED\n");
+ tools_sequence = true;
+ }
+ }
+
+ ADD_INTERNAL_CALL_REGISTRATION(E->get());
+ }
+
+ if (tools_sequence) {
+ tools_sequence = false;
+ output.push_back("#endif\n");
+ }
+
+ output.push_back("#ifdef TOOLS_ENABLED\n");
+ for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next())
+ ADD_INTERNAL_CALL_REGISTRATION(E->get());
+ output.push_back("#endif // TOOLS_ENABLED\n");
+
+ for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) {
+ if (tools_sequence) {
+ if (!E->get().editor_only) {
+ tools_sequence = false;
+ output.push_back("#endif\n");
+ }
+ } else {
+ if (E->get().editor_only) {
+ output.push_back("#ifdef TOOLS_ENABLED\n");
+ tools_sequence = true;
+ }
+ }
+
+ ADD_INTERNAL_CALL_REGISTRATION(E->get());
+ }
+
+ if (tools_sequence) {
+ tools_sequence = false;
+ output.push_back("#endif\n");
+ }
+
+#undef ADD_INTERNAL_CALL_REGISTRATION
+
+ output.push_back(CLOSE_BLOCK "}\n");
+
+ Error save_err = _save_file(path_join(p_output_dir, "mono_glue.gen.cpp"), output);
+ if (save_err != OK)
+ return save_err;
+
+ OS::get_singleton()->print("Mono glue generated successfully\n");
+
+ return OK;
+}
+
+Error BindingsGenerator::_save_file(const String &p_path, const List<String> &p_content) {
+
+ FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
+
+ ERR_EXPLAIN("Cannot open file: " + p_path);
+ ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
+
+ for (const List<String>::Element *E = p_content.front(); E; E = E->next()) {
+ file->store_string(E->get());
+ }
+
+ file->close();
+
+ return OK;
+}
+
+Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, List<String> &p_output) {
+
+ if (p_imethod.is_virtual)
+ return OK; // Ignore
+
+ bool ret_void = p_imethod.return_type == "void";
+
+ const TypeInterface *return_type = _get_type_by_name_or_placeholder(p_imethod.return_type);
+
+ String argc_str = itos(p_imethod.arguments.size());
+
+ String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
+ String c_in_statements;
+ String c_args_var_content;
+
+ // Get arguments information
+ int i = 0;
+ for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) {
+ const ArgumentInterface &iarg = F->get();
+ const TypeInterface *arg_type = _get_type_by_name_or_placeholder(iarg.type);
+
+ String c_param_name = "arg" + itos(i + 1);
+
+ if (p_imethod.is_vararg) {
+ if (i < p_imethod.arguments.size() - 1) {
+ c_in_statements += sformat(arg_type->c_in.size() ? arg_type->c_in : TypeInterface::DEFAULT_VARARG_C_IN, "Variant", c_param_name);
+ c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(0, ";
+ c_in_statements += sformat("&%s_in", c_param_name);
+ c_in_statements += ");\n";
+ }
+ } else {
+ if (i > 0)
+ c_args_var_content += ", ";
+ if (arg_type->c_in.size())
+ c_in_statements += sformat(arg_type->c_in, arg_type->c_type, c_param_name);
+ c_args_var_content += sformat(arg_type->c_arg_in, c_param_name);
+ }
+
+ c_func_sig += ", ";
+ c_func_sig += arg_type->c_type_in;
+ c_func_sig += " ";
+ c_func_sig += c_param_name;
+
+ i++;
+ }
+
+ const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ ERR_FAIL_NULL_V(match, ERR_BUG);
+
+ const InternalCall *im_icall = match->value();
+ String icall_method = im_icall->name;
+
+ if (!generated_icall_funcs.find(im_icall)) {
+ generated_icall_funcs.push_back(im_icall);
+
+ if (im_icall->editor_only)
+ p_output.push_back("#ifdef TOOLS_ENABLED\n");
+
+ // Generate icall function
+
+ p_output.push_back(ret_void ? "void " : return_type->c_type_out + " ");
+ p_output.push_back(icall_method);
+ p_output.push_back("(");
+ p_output.push_back(c_func_sig);
+ p_output.push_back(") " OPEN_BLOCK);
+
+ String fail_ret = ret_void ? "" : ", " + (return_type->c_type_out.ends_with("*") ? "NULL" : return_type->c_type_out + "()");
+
+ if (!ret_void) {
+ String ptrcall_return_type;
+ String initialization;
+
+ if (return_type->is_object_type) {
+ ptrcall_return_type = return_type->is_reference ? "Ref<Reference>" : return_type->c_type;
+ initialization = return_type->is_reference ? "" : " = NULL";
+ } else {
+ ptrcall_return_type = return_type->c_type;
+ }
+
+ p_output.push_back("\t" + ptrcall_return_type);
+ p_output.push_back(" " LOCAL_RET);
+ p_output.push_back(initialization + ";\n");
+ p_output.push_back("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE);
+ p_output.push_back(fail_ret);
+ p_output.push_back(");\n");
+ } else {
+ p_output.push_back("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
+ }
+
+ if (p_imethod.arguments.size()) {
+ if (p_imethod.is_vararg) {
+ String err_fail_macro = ret_void ? "ERR_FAIL_COND" : "ERR_FAIL_COND_V";
+ String vararg_arg = "arg" + argc_str;
+ String real_argc_str = itos(p_imethod.arguments.size() - 1); // Arguments count without vararg
+
+ p_output.push_back("\tVector<Variant> varargs;\n"
+ "\tint vararg_length = mono_array_length(");
+ p_output.push_back(vararg_arg);
+ p_output.push_back(");\n\tint total_length = ");
+ p_output.push_back(real_argc_str);
+ p_output.push_back(" + vararg_length;\n\t");
+ p_output.push_back(err_fail_macro);
+ p_output.push_back("(varargs.resize(vararg_length) != OK");
+ p_output.push_back(fail_ret);
+ p_output.push_back(");\n\tVector<Variant*> " C_LOCAL_PTRCALL_ARGS ";\n\t");
+ p_output.push_back(err_fail_macro);
+ p_output.push_back("(call_args.resize(total_length) != OK");
+ p_output.push_back(fail_ret);
+ p_output.push_back(");\n");
+ p_output.push_back(c_in_statements);
+ p_output.push_back("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
+ "\t\tMonoObject* elem = mono_array_get(");
+ p_output.push_back(vararg_arg);
+ p_output.push_back(", MonoObject*, i);\n"
+ "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n"
+ "\t\t" C_LOCAL_PTRCALL_ARGS ".set(");
+ p_output.push_back(real_argc_str);
+ p_output.push_back(" + i, &varargs[i]);\n\t" CLOSE_BLOCK);
+ } else {
+ p_output.push_back(c_in_statements);
+ p_output.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
+ p_output.push_back(argc_str + "] = { ");
+ p_output.push_back(c_args_var_content + " };\n");
+ }
+ }
+
+ if (p_imethod.is_vararg) {
+ p_output.push_back("\tVariant::CallError vcall_error;\n\t");
+
+ if (!ret_void)
+ p_output.push_back(LOCAL_RET " = ");
+
+ p_output.push_back(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
+ p_output.push_back(p_imethod.arguments.size() ? "(const Variant**)" C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
+ p_output.push_back(", total_length, vcall_error);\n");
+ } else {
+ p_output.push_back("\t" CS_PARAM_METHODBIND "->ptrcall(" CS_PARAM_INSTANCE ", ");
+ p_output.push_back(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "NULL, ");
+ p_output.push_back(!ret_void ? "&" LOCAL_RET ");\n" : "NULL);\n");
+ }
+
+ if (!ret_void) {
+ if (return_type->c_out.empty())
+ p_output.push_back("\treturn " LOCAL_RET ";\n");
+ else
+ p_output.push_back(sformat(return_type->c_out, return_type->c_type_out, LOCAL_RET, return_type->name));
+ }
+
+ p_output.push_back(CLOSE_BLOCK "\n");
+
+ if (im_icall->editor_only)
+ p_output.push_back("#endif // TOOLS_ENABLED\n");
+ }
+
+ return OK;
+}
+
+const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_null(const String &p_name) {
+
+ const Map<String, TypeInterface>::Element *match = builtin_types.find(p_name);
+
+ if (match)
+ return &match->get();
+
+ match = obj_types.find(p_name);
+
+ if (match)
+ return &match->get();
+
+ return NULL;
+}
+
+const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_by_name_or_placeholder(const String &p_name) {
+
+ const TypeInterface *found = _get_type_by_name_or_null(p_name);
+
+ if (found)
+ return found;
+
+ ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_name);
+
+ const Map<String, TypeInterface>::Element *match = placeholder_types.find(p_name);
+
+ if (match)
+ return &match->get();
+
+ TypeInterface placeholder;
+ TypeInterface::create_placeholder_type(placeholder, p_name);
+
+ return &placeholder_types.insert(placeholder.name, placeholder)->get();
+}
+
+void BindingsGenerator::_populate_object_type_interfaces() {
+
+ obj_types.clear();
+
+ List<StringName> class_list;
+ ClassDB::get_class_list(&class_list);
+ class_list.sort_custom<StringName::AlphCompare>();
+
+ StringName refclass_name = String("Reference");
+
+ while (class_list.size()) {
+ StringName type_cname = class_list.front()->get();
+
+ ClassDB::APIType api_type = ClassDB::get_api_type(type_cname);
+
+ if (api_type == ClassDB::API_NONE) {
+ class_list.pop_front();
+ continue;
+ }
+
+ TypeInterface itype = TypeInterface::create_object_type(type_cname, api_type);
+
+ itype.base_name = ClassDB::get_parent_class(type_cname);
+ itype.is_singleton = ProjectSettings::get_singleton()->has_singleton(itype.proxy_name);
+ itype.is_instantiable = ClassDB::can_instance(type_cname) && !itype.is_singleton;
+ itype.is_reference = ClassDB::is_parent_class(type_cname, refclass_name);
+ itype.memory_own = itype.is_reference;
+
+ if (!ClassDB::is_class_exposed(type_cname)) {
+ if (verbose_output)
+ WARN_PRINTS("Ignoring type " + String(type_cname) + " because it's not exposed");
+ class_list.pop_front();
+ continue;
+ }
+
+ itype.c_out = "\treturn ";
+ itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED;
+ itype.c_out += itype.is_reference ? "(%1.ptr());\n" : "(%1);\n";
+
+ itype.cs_in = itype.is_singleton ? BINDINGS_PTR_FIELD : "Object." CS_SMETHOD_GETINSTANCE "(%0)";
+
+ itype.c_type = "Object*";
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = "MonoObject*";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = "IntPtr";
+ itype.im_type_out = itype.proxy_name;
+
+ List<MethodInfo> virtual_method_list;
+ ClassDB::get_virtual_methods(type_cname, &virtual_method_list, true);
+
+ List<MethodInfo> method_list;
+ ClassDB::get_method_list(type_cname, &method_list, true);
+ method_list.sort();
+
+ for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
+ const MethodInfo &method_info = E->get();
+
+ int argc = method_info.arguments.size();
+
+ if (method_info.name.empty())
+ continue;
+
+ MethodInterface imethod;
+ imethod.name = method_info.name;
+
+ if (method_info.flags & METHOD_FLAG_VIRTUAL)
+ imethod.is_virtual = true;
+
+ PropertyInfo return_info = method_info.return_val;
+
+ MethodBind *m = imethod.is_virtual ? NULL : ClassDB::get_method(type_cname, method_info.name);
+
+ imethod.is_vararg = m && m->is_vararg();
+
+ if (!m && !imethod.is_virtual) {
+ if (virtual_method_list.find(method_info)) {
+ // A virtual method without the virtual flag. This is a special case.
+
+ // This type of method can only be found in Object derived types.
+ ERR_FAIL_COND(!itype.is_object_type);
+
+ // There is no method bind, so let's fallback to Godot's object.Call(string, params)
+ imethod.requires_object_call = true;
+
+ // The method Object.free is registered as a virtual method, but without the virtual flag.
+ // This is because this method is not supposed to be overridden, but called.
+ // We assume the return type is void.
+ imethod.return_type = "void";
+
+ // Actually, more methods like this may be added in the future,
+ // which could actually will return something differnet.
+ // Let's put this to notify us if that ever happens.
+ if (itype.name != "Object" || imethod.name != "free") {
+ if (verbose_output) {
+ WARN_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
+ "We only expected Object.free, but found " +
+ itype.name + "." + imethod.name);
+ }
+ }
+ } else {
+ ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
+ }
+ } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ //imethod.return_type = return_info.class_name;
+ imethod.return_type = "int";
+ } else if (return_info.class_name != StringName()) {
+ imethod.return_type = return_info.class_name;
+ } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ imethod.return_type = return_info.hint_string;
+ } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
+ imethod.return_type = "Variant";
+ } else if (return_info.type == Variant::NIL) {
+ imethod.return_type = "void";
+ } else {
+ imethod.return_type = Variant::get_type_name(return_info.type);
+ }
+
+ if (!itype.requires_collections && imethod.return_type == "Dictionary")
+ itype.requires_collections = true;
+
+ for (int i = 0; i < argc; i++) {
+ PropertyInfo arginfo = method_info.arguments[i];
+
+ ArgumentInterface iarg;
+ iarg.name = arginfo.name;
+
+ if (arginfo.type == Variant::INT && arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
+ //iarg.type = arginfo.class_name;
+ iarg.type = "int";
+ } else if (arginfo.class_name != StringName()) {
+ iarg.type = arginfo.class_name;
+ } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ iarg.type = arginfo.hint_string;
+ } else if (arginfo.type == Variant::NIL) {
+ iarg.type = "Variant";
+ } else {
+ iarg.type = Variant::get_type_name(arginfo.type);
+ }
+
+ iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
+
+ if (!itype.requires_collections && iarg.type == "Dictionary")
+ itype.requires_collections = true;
+
+ if (m && m->has_default_argument(i)) {
+ _default_argument_from_variant(m->get_default_argument(i), iarg);
+ }
+
+ imethod.add_argument(iarg);
+ }
+
+ if (imethod.is_vararg) {
+ ArgumentInterface ivararg;
+ ivararg.type = "VarArg";
+ ivararg.name = "@args";
+ imethod.add_argument(ivararg);
+ }
+
+ imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(imethod.name));
+
+ // Prevent naming the property and its enclosing type from sharing the same name
+ if (imethod.proxy_name == itype.proxy_name) {
+ if (verbose_output) {
+ WARN_PRINTS("Name of method `" + imethod.proxy_name + "` is ambiguous with the name of its class `" +
+ itype.proxy_name + "`. Renaming method to `" + imethod.proxy_name + "_`");
+ }
+
+ imethod.proxy_name += "_";
+ }
+
+ if (itype.class_doc) {
+ for (int i = 0; i < itype.class_doc->methods.size(); i++) {
+ if (itype.class_doc->methods[i].name == imethod.name) {
+ imethod.method_doc = &itype.class_doc->methods[i];
+ break;
+ }
+ }
+ }
+
+ if (!imethod.is_virtual && imethod.name[0] == '_') {
+ const Vector<DocData::PropertyDoc> &properties = itype.class_doc->properties;
+
+ for (int i = 0; i < properties.size(); i++) {
+ const DocData::PropertyDoc &prop_doc = properties[i];
+
+ if (prop_doc.getter == imethod.name || prop_doc.setter == imethod.name) {
+ imethod.is_internal = true;
+ itype.methods.push_back(imethod);
+ break;
+ }
+ }
+ } else {
+ itype.methods.push_back(imethod);
+ }
+ }
+
+ obj_types.insert(itype.name, itype);
+
+ class_list.pop_front();
+ }
+}
+
+void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg) {
+
+ r_iarg.default_argument = p_val;
+
+ switch (p_val.get_type()) {
+ case Variant::NIL:
+ if (ClassDB::class_exists(r_iarg.type)) {
+ // Object type
+ r_iarg.default_argument = "null";
+ } else {
+ // Variant
+ r_iarg.default_argument = "null";
+ }
+ break;
+ // Atomic types
+ case Variant::BOOL:
+ r_iarg.default_argument = bool(p_val) ? "true" : "false";
+ break;
+ case Variant::INT:
+ break; // Keep it
+ case Variant::REAL:
+#ifndef REAL_T_IS_DOUBLE
+ r_iarg.default_argument += "f";
+#endif
+ break;
+ case Variant::STRING:
+ case Variant::NODE_PATH:
+ r_iarg.default_argument = "\"" + r_iarg.default_argument + "\"";
+ break;
+ case Variant::TRANSFORM:
+ if (p_val.operator Transform() == Transform())
+ r_iarg.default_argument.clear();
+ r_iarg.default_argument = "new %s(" + r_iarg.default_argument + ")";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ break;
+ case Variant::PLANE:
+ case Variant::RECT3:
+ case Variant::COLOR:
+ r_iarg.default_argument = "new Color(1, 1, 1, 1)";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ break;
+ case Variant::VECTOR2:
+ case Variant::RECT2:
+ case Variant::VECTOR3:
+ r_iarg.default_argument = "new %s" + r_iarg.default_argument;
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ break;
+ case Variant::OBJECT:
+ if (p_val.is_zero()) {
+ r_iarg.default_argument = "null";
+ break;
+ }
+ case Variant::DICTIONARY:
+ case Variant::_RID:
+ r_iarg.default_argument = "new %s()";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ break;
+ case Variant::ARRAY:
+ case Variant::POOL_BYTE_ARRAY:
+ case Variant::POOL_INT_ARRAY:
+ case Variant::POOL_REAL_ARRAY:
+ case Variant::POOL_STRING_ARRAY:
+ case Variant::POOL_VECTOR2_ARRAY:
+ case Variant::POOL_VECTOR3_ARRAY:
+ case Variant::POOL_COLOR_ARRAY:
+ r_iarg.default_argument = "new %s {}";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ break;
+ case Variant::TRANSFORM2D:
+ case Variant::BASIS:
+ case Variant::QUAT:
+ r_iarg.default_argument = Variant::get_type_name(p_val.get_type()) + ".Identity";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
+ break;
+ default: {}
+ }
+
+ if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type == "Variant" && r_iarg.default_argument != "null")
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+}
+
+void BindingsGenerator::_populate_builtin_type_interfaces() {
+
+ builtin_types.clear();
+
+ TypeInterface itype;
+
+#define INSERT_STRUCT_TYPE(m_type, m_type_in) \
+ { \
+ itype = TypeInterface::create_value_type(#m_type); \
+ itype.c_in = "\tMARSHALLED_IN(" #m_type ", %1, %1_in);\n"; \
+ itype.c_out = "\tMARSHALLED_OUT(" #m_type ", %1, ret_out)\n" \
+ "\treturn mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(%2), ret_out);\n"; \
+ itype.c_arg_in = "&%s_in"; \
+ itype.c_type_in = m_type_in; \
+ itype.cs_in = "ref %s"; \
+ itype.cs_out = "return (" #m_type ")%0;"; \
+ itype.im_type_out = "object"; \
+ builtin_types.insert(#m_type, itype); \
+ }
+
+ INSERT_STRUCT_TYPE(Vector2, "real_t*")
+ INSERT_STRUCT_TYPE(Rect2, "real_t*")
+ INSERT_STRUCT_TYPE(Transform2D, "real_t*")
+ INSERT_STRUCT_TYPE(Vector3, "real_t*")
+ INSERT_STRUCT_TYPE(Basis, "real_t*")
+ INSERT_STRUCT_TYPE(Quat, "real_t*")
+ INSERT_STRUCT_TYPE(Transform, "real_t*")
+ INSERT_STRUCT_TYPE(Rect3, "real_t*")
+ INSERT_STRUCT_TYPE(Color, "real_t*")
+ INSERT_STRUCT_TYPE(Plane, "real_t*")
+
+#undef INSERT_STRUCT_TYPE
+
+#define INSERT_PRIMITIVE_TYPE(m_type) \
+ { \
+ itype = TypeInterface::create_value_type(#m_type); \
+ itype.c_arg_in = "&%s"; \
+ itype.c_type_in = #m_type; \
+ itype.c_type_out = #m_type; \
+ itype.im_type_in = #m_type; \
+ itype.im_type_out = #m_type; \
+ builtin_types.insert(#m_type, itype); \
+ }
+
+ INSERT_PRIMITIVE_TYPE(bool)
+ //INSERT_PRIMITIVE_TYPE(int)
+
+ // int
+ itype = TypeInterface::create_value_type("int");
+ itype.c_arg_in = "&%s_in";
+ //* ptrcall only supports int64_t and uint64_t
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "int64_t";
+ //*/
+ itype.c_type_in = itype.name;
+ itype.c_type_out = itype.name;
+ itype.im_type_in = itype.name;
+ itype.im_type_out = itype.name;
+ builtin_types.insert(itype.name, itype);
+
+#undef INSERT_PRIMITIVE_TYPE
+
+ // real_t
+ itype = TypeInterface();
+#ifdef REAL_T_IS_DOUBLE
+ itype.name = "double";
+#else
+ itype.name = "float";
+#endif
+ itype.proxy_name = itype.name;
+ itype.c_arg_in = "&%s_in";
+ //* ptrcall only supports double
+ 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 = "real_t";
+ itype.c_type_out = "real_t";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
+ builtin_types.insert(itype.name, itype);
+
+ // String
+ itype = TypeInterface();
+ itype.name = "String";
+ itype.proxy_name = "string";
+ itype.c_in = "\t%0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n";
+ itype.c_out = "\treturn " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = itype.name;
+ itype.c_type_in = "MonoString*";
+ itype.c_type_out = "MonoString*";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
+ builtin_types.insert(itype.name, itype);
+
+ // NodePath
+ itype = TypeInterface();
+ itype.name = "NodePath";
+ itype.proxy_name = "NodePath";
+ itype.c_out = "\treturn memnew(NodePath(%1));\n";
+ itype.c_type = itype.name;
+ itype.c_type_in = itype.c_type + "*";
+ itype.c_type_out = itype.c_type + "*";
+ itype.cs_type = itype.proxy_name;
+ itype.cs_in = "NodePath." CS_SMETHOD_GETINSTANCE "(%0)";
+ itype.cs_out = "return new NodePath(%0);";
+ itype.im_type_in = "IntPtr";
+ itype.im_type_out = "IntPtr";
+ _populate_builtin_type(itype, Variant::NODE_PATH);
+ extra_members.insert(itype.name, MEMBER_BEGIN "public NodePath() : this(string.Empty) {}\n" MEMBER_BEGIN "public NodePath(string path)\n" OPEN_BLOCK_L2
+ "this." BINDINGS_PTR_FIELD " = NativeCalls.godot_icall_NodePath_Ctor(path);\n" CLOSE_BLOCK_L2
+ MEMBER_BEGIN "public static implicit operator NodePath(string from)\n" OPEN_BLOCK_L2 "return new NodePath(from);\n" CLOSE_BLOCK_L2
+ MEMBER_BEGIN "public static implicit operator string(NodePath from)\n" OPEN_BLOCK_L2
+ "return NativeCalls." ICALL_PREFIX "NodePath_operator_String(NodePath." CS_SMETHOD_GETINSTANCE "(from));\n" CLOSE_BLOCK_L2);
+ builtin_types.insert(itype.name, itype);
+
+ // RID
+ itype = TypeInterface();
+ itype.name = "RID";
+ itype.proxy_name = "RID";
+ itype.c_out = "\treturn memnew(RID(%1));\n";
+ itype.c_type = itype.name;
+ itype.c_type_in = itype.c_type + "*";
+ itype.c_type_out = itype.c_type + "*";
+ itype.cs_type = itype.proxy_name;
+ itype.cs_in = "RID." CS_SMETHOD_GETINSTANCE "(%0)";
+ itype.cs_out = "return new RID(%0);";
+ itype.im_type_in = "IntPtr";
+ itype.im_type_out = "IntPtr";
+ _populate_builtin_type(itype, Variant::_RID);
+ extra_members.insert(itype.name, MEMBER_BEGIN "internal RID()\n" OPEN_BLOCK_L2
+ "this." BINDINGS_PTR_FIELD " = IntPtr.Zero;\n" CLOSE_BLOCK_L2);
+ builtin_types.insert(itype.name, itype);
+
+ // Variant
+ itype = TypeInterface();
+ itype.name = "Variant";
+ itype.proxy_name = "object";
+ itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_VARIANT "(%1);\n";
+ itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_VARIANT "(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = itype.name;
+ itype.c_type_in = "MonoObject*";
+ itype.c_type_out = "MonoObject*";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = "object";
+ itype.im_type_out = itype.proxy_name;
+ builtin_types.insert(itype.name, itype);
+
+ // VarArg (fictitious type to represent variable arguments)
+ itype = TypeInterface();
+ itype.name = "VarArg";
+ itype.proxy_name = "object[]";
+ itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(Array) "(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = "Array";
+ itype.c_type_in = "MonoArray*";
+ itype.cs_type = "params object[]";
+ itype.im_type_in = "object[]";
+ builtin_types.insert(itype.name, itype);
+
+#define INSERT_ARRAY_FULL(m_name, m_type, m_proxy_t) \
+ { \
+ itype = TypeInterface(); \
+ itype.name = #m_name; \
+ itype.proxy_name = #m_proxy_t "[]"; \
+ itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
+ itype.c_out = "\treturn " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
+ itype.c_arg_in = "&%s_in"; \
+ itype.c_type = #m_type; \
+ itype.c_type_in = "MonoArray*"; \
+ itype.c_type_out = "MonoArray*"; \
+ itype.cs_type = itype.proxy_name; \
+ itype.im_type_in = itype.proxy_name; \
+ itype.im_type_out = itype.proxy_name; \
+ builtin_types.insert(itype.name, itype); \
+ }
+
+#define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
+
+ INSERT_ARRAY(Array, object);
+ INSERT_ARRAY(PoolIntArray, int);
+ INSERT_ARRAY_FULL(PoolByteArray, PoolByteArray, byte);
+
+#ifdef REAL_T_IS_DOUBLE
+ INSERT_ARRAY(PoolRealArray, double);
+#else
+ INSERT_ARRAY(PoolRealArray, float);
+#endif
+
+ INSERT_ARRAY(PoolStringArray, string);
+
+ INSERT_ARRAY(PoolColorArray, Color);
+ INSERT_ARRAY(PoolVector2Array, Vector2);
+ INSERT_ARRAY(PoolVector3Array, Vector3);
+
+#undef INSERT_ARRAY
+
+ // Dictionary
+ itype = TypeInterface();
+ itype.name = "Dictionary";
+ itype.proxy_name = "Dictionary<object, object>";
+ itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_DICT "(%1);\n";
+ itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_DICT "(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = itype.name;
+ itype.c_type_in = "MonoObject*";
+ itype.c_type_out = "MonoObject*";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
+ builtin_types.insert(itype.name, itype);
+
+ // void (fictitious type to represent the return type of methods that do not return anything)
+ itype = TypeInterface();
+ itype.name = "void";
+ itype.proxy_name = itype.name;
+ itype.c_type = itype.name;
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.c_type;
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
+ builtin_types.insert(itype.name, itype);
+
+ // Error
+ itype = TypeInterface();
+ itype.name = "Error";
+ itype.proxy_name = "Error";
+ itype.c_type = itype.name;
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.c_type;
+ itype.cs_type = itype.proxy_name;
+ itype.cs_in = "(int)%0";
+ itype.cs_out = "return (Error)%s;";
+ itype.im_type_in = "int";
+ itype.im_type_out = "int";
+ builtin_types.insert(itype.name, itype);
+}
+
+void BindingsGenerator::_populate_builtin_type(TypeInterface &r_itype, Variant::Type vtype) {
+
+ Variant::CallError cerror;
+ Variant v = Variant::construct(vtype, NULL, 0, cerror);
+
+ List<MethodInfo> method_list;
+ v.get_method_list(&method_list);
+ method_list.sort();
+
+ for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
+ MethodInfo &mi = E->get();
+ MethodInterface imethod;
+
+ imethod.name = mi.name;
+ imethod.proxy_name = mi.name;
+
+ for (int i = 0; i < mi.arguments.size(); i++) {
+ ArgumentInterface iarg;
+ PropertyInfo pi = mi.arguments[i];
+
+ iarg.name = pi.name;
+
+ if (pi.type == Variant::NIL)
+ iarg.type = "Variant";
+ else
+ iarg.type = Variant::get_type_name(pi.type);
+
+ if (!r_itype.requires_collections && iarg.type == "Dictionary")
+ r_itype.requires_collections = true;
+
+ if ((mi.default_arguments.size() - mi.arguments.size() + i) >= 0)
+ _default_argument_from_variant(Variant::construct(pi.type, NULL, 0, cerror), iarg);
+
+ imethod.add_argument(iarg);
+ }
+
+ if (mi.return_val.type == Variant::NIL) {
+ if (mi.return_val.name != "")
+ imethod.return_type = "Variant";
+ } else {
+ imethod.return_type = Variant::get_type_name(mi.return_val.type);
+ }
+
+ if (!r_itype.requires_collections && imethod.return_type == "Dictionary")
+ r_itype.requires_collections = true;
+
+ if (r_itype.class_doc) {
+ for (int i = 0; i < r_itype.class_doc->methods.size(); i++) {
+ if (r_itype.class_doc->methods[i].name == imethod.name) {
+ imethod.method_doc = &r_itype.class_doc->methods[i];
+ break;
+ }
+ }
+ }
+
+ r_itype.methods.push_back(imethod);
+ }
+}
+
+BindingsGenerator::BindingsGenerator() {
+
+ EditorHelp::generate_doc();
+
+ _populate_object_type_interfaces();
+ _populate_builtin_type_interfaces();
+ _generate_header_icalls();
+
+ for (Map<String, TypeInterface>::Element *E = obj_types.front(); E; E = E->next())
+ _generate_method_icalls(E->get());
+
+ _generate_method_icalls(builtin_types["NodePath"]);
+ _generate_method_icalls(builtin_types["RID"]);
+}
+
+void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
+
+ const int NUM_OPTIONS = 3;
+ int options_left = NUM_OPTIONS;
+
+ String mono_glue_option = "--generate-mono-glue";
+ String cs_core_api_option = "--generate-cs-core-api";
+ String cs_editor_api_option = "--generate-cs-editor-api";
+
+ verbose_output = true;
+
+ const List<String>::Element *elem = p_cmdline_args.front();
+
+ while (elem && options_left) {
+
+ if (elem->get() == mono_glue_option) {
+
+ const List<String>::Element *path_elem = elem->next();
+
+ if (path_elem) {
+ if (get_singleton().generate_glue(path_elem->get()) != OK)
+ ERR_PRINT("Mono glue generation failed");
+ elem = elem->next();
+ } else {
+ ERR_PRINTS("--generate-mono-glue: No output directory specified");
+ }
+
+ --options_left;
+
+ } else if (elem->get() == cs_core_api_option) {
+
+ const List<String>::Element *path_elem = elem->next();
+
+ if (path_elem) {
+ if (get_singleton().generate_cs_core_project(path_elem->get()) != OK)
+ ERR_PRINT("Generation of solution and C# project for the Core API failed");
+ elem = elem->next();
+ } else {
+ ERR_PRINTS(cs_core_api_option + ": No output directory specified");
+ }
+
+ --options_left;
+
+ } else if (elem->get() == cs_editor_api_option) {
+
+ const List<String>::Element *path_elem = elem->next();
+
+ if (path_elem) {
+ if (path_elem->next()) {
+ if (get_singleton().generate_cs_editor_project(path_elem->get(), path_elem->next()->get()) != OK)
+ ERR_PRINT("Generation of solution and C# project for the Editor API failed");
+ elem = path_elem->next();
+ } else {
+ ERR_PRINTS(cs_editor_api_option + ": No hint path for the Core API dll specified");
+ }
+ } else {
+ ERR_PRINTS(cs_editor_api_option + ": No output directory specified");
+ }
+
+ --options_left;
+ }
+
+ elem = elem->next();
+ }
+
+ verbose_output = false;
+
+ if (options_left != NUM_OPTIONS)
+ exit(0);
+}
+
+#endif
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
new file mode 100644
index 0000000000..dfa3aa9911
--- /dev/null
+++ b/modules/mono/editor/bindings_generator.h
@@ -0,0 +1,436 @@
+/*************************************************************************/
+/* bindings_generator.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef BINDINGS_GENERATOR_H
+#define BINDINGS_GENERATOR_H
+
+#include "class_db.h"
+#include "editor/doc/doc_data.h"
+#include "editor/editor_help.h"
+
+#ifdef DEBUG_METHODS_ENABLED
+
+#include "ustring.h"
+
+class BindingsGenerator {
+ struct ArgumentInterface {
+ enum DefaultParamMode {
+ CONSTANT,
+ NULLABLE_VAL,
+ NULLABLE_REF
+ };
+
+ String type;
+ String name;
+ String default_argument;
+ DefaultParamMode def_param_mode;
+
+ ArgumentInterface() {
+ def_param_mode = CONSTANT;
+ }
+ };
+
+ struct MethodInterface {
+ String name;
+
+ /**
+ * Name of the C# method
+ */
+ String proxy_name;
+
+ /**
+ * [TypeInterface::name] of the return type
+ */
+ String return_type;
+
+ /**
+ * Determines if the method has a variable number of arguments (VarArg)
+ */
+ bool is_vararg;
+
+ /**
+ * Virtual methods ("virtual" as defined by the Godot API) are methods that by default do nothing,
+ * but can be overridden by the user to add custom functionality.
+ * e.g.: _ready, _process, etc.
+ */
+ bool is_virtual;
+
+ /**
+ * Determines if the call should fallback to Godot's object.Call(string, params) in C#.
+ */
+ bool requires_object_call;
+
+ /**
+ * Determines if the method visibility is `internal` (visible only to files in the same assembly).
+ * Currently, we only use this for methods that are not meant to be exposed,
+ * but are required by properties as getters or setters.
+ * Methods that are not meant to be exposed are those that begin with underscore and are not virtual.
+ */
+ bool is_internal;
+
+ List<ArgumentInterface> arguments;
+
+ const DocData::MethodDoc *method_doc;
+
+ void add_argument(const ArgumentInterface &argument) {
+ arguments.push_back(argument);
+ }
+
+ MethodInterface() {
+ return_type = "void";
+ is_vararg = false;
+ is_virtual = false;
+ requires_object_call = false;
+ is_internal = false;
+ method_doc = NULL;
+ }
+ };
+
+ struct TypeInterface {
+ /**
+ * Identifier name for this type.
+ * Also used to format [c_out].
+ */
+ String name;
+
+ /**
+ * Identifier name of the base class.
+ */
+ String base_name;
+
+ /**
+ * Name of the C# class
+ */
+ String proxy_name;
+
+ ClassDB::APIType api_type;
+
+ bool is_object_type;
+ bool is_singleton;
+ bool is_reference;
+
+ /**
+ * Used only by Object-derived types.
+ * Determines if this type is not virtual (incomplete).
+ * e.g.: CanvasItem cannot be instantiated.
+ */
+ bool is_instantiable;
+
+ /**
+ * Used only by Object-derived types.
+ * Determines if the C# class owns the native handle and must free it somehow when disposed.
+ * e.g.: Reference types must notify when the C# instance is disposed, for proper refcounting.
+ */
+ bool memory_own;
+
+ /**
+ * Determines if the file must have a using directive for System.Collections.Generic
+ * e.g.: When the generated class makes use of Dictionary
+ */
+ bool requires_collections;
+
+ // !! The comments of the following fields make reference to other fields via square brackets, e.g.: [field_name]
+ // !! When renaming those fields, make sure to rename their references in the comments
+
+ // --- C INTERFACE ---
+
+ static const char *DEFAULT_VARARG_C_IN;
+
+ /**
+ * One or more statements that manipulate the parameter before being passed as argument of a ptrcall.
+ * If the statement adds a local that must be passed as the argument instead of the parameter,
+ * the name of that local must be specified with [c_arg_in].
+ * For variadic methods, this field is required and, if empty, [DEFAULT_VARARG_C_IN] is used instead.
+ * Formatting elements:
+ * %0: [c_type] of the parameter
+ * %1: name of the parameter
+ */
+ String c_in;
+
+ /**
+ * Determines the name of the variable that will be passed as argument to a ptrcall.
+ * By default the value equals the name of the parameter,
+ * this varies for types that require special manipulation via [c_in].
+ * Formatting elements:
+ * %0 or %s: name of the parameter
+ */
+ String c_arg_in;
+
+ /**
+ * One or more statements that determine how a variable of this type is returned from a function.
+ * It must contain the return statement(s).
+ * Formatting elements:
+ * %0: [c_type_out] of the return type
+ * %1: name of the variable to be returned
+ * %2: [name] of the return type
+ */
+ String c_out;
+
+ /**
+ * The actual expected type, as seen (in most cases) in Variant copy constructors
+ * Used for the type of the return variable and to format [c_in].
+ * The value must be the following depending of the type:
+ * Object-derived types: Object*
+ * Other types: [name]
+ * -- Exceptions --
+ * VarArg (fictitious type to represent variable arguments): Array
+ * float: double (because ptrcall only supports double)
+ * int: int64_t (because ptrcall only supports int64_t and uint64_t)
+ * Reference types override this for the type of the return variable: Ref<Reference>
+ */
+ String c_type;
+
+ /**
+ * Determines the type used for parameters in function signatures.
+ */
+ String c_type_in;
+
+ /**
+ * Determines the return type used for function signatures.
+ * Also used to construct a default value to return in case of errors,
+ * and to format [c_out].
+ */
+ String c_type_out;
+
+ // --- C# INTERFACE ---
+
+ /**
+ * An expression that overrides the way the parameter is passed to the internal call.
+ * If empty, the parameter is passed as is.
+ * Formatting elements:
+ * %0 or %s: name of the parameter
+ */
+ String cs_in;
+
+ /**
+ * One or more statements that determine how a variable of this type is returned from a method.
+ * It must contain the return statement(s).
+ * Formatting elements:
+ * %0 or %s: name of the variable to be returned
+ */
+ String cs_out;
+
+ /**
+ * Type used for method signatures, both for parameters and the return type.
+ * Same as [proxy_name] except for variable arguments (VarArg).
+ */
+ String cs_type;
+
+ /**
+ * Type used for parameters of internal call methods.
+ */
+ String im_type_in;
+
+ /**
+ * Type used for the return type of internal call methods.
+ * If [cs_out] is not empty and the method return type is not void,
+ * it is also used for the type of the return variable.
+ */
+ String im_type_out;
+
+ const DocData::ClassDoc *class_doc;
+
+ List<MethodInterface> methods;
+
+ const MethodInterface *find_method_by_name(const String &p_name) const {
+
+ for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) {
+ if (E->get().name == p_name)
+ return &E->get();
+ }
+
+ return NULL;
+ }
+
+ static TypeInterface create_value_type(const String &p_name) {
+ TypeInterface itype;
+
+ itype.name = p_name;
+ itype.proxy_name = p_name;
+
+ itype.c_type = itype.name;
+ itype.c_type_in = "void*";
+ itype.c_type_out = "MonoObject*";
+ itype.cs_type = itype.proxy_name;
+ itype.im_type_in = "ref " + itype.proxy_name;
+ itype.im_type_out = itype.proxy_name;
+ itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
+
+ return itype;
+ }
+
+ static TypeInterface create_object_type(const String &p_name, ClassDB::APIType p_api_type) {
+ TypeInterface itype;
+
+ itype.name = p_name;
+ itype.proxy_name = p_name.begins_with("_") ? p_name.substr(1, p_name.length()) : p_name;
+ itype.api_type = p_api_type;
+ itype.is_object_type = true;
+ itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
+
+ return itype;
+ }
+
+ static void create_placeholder_type(TypeInterface &r_itype, const String &p_name) {
+ r_itype.name = p_name;
+ r_itype.proxy_name = p_name;
+
+ r_itype.c_type = r_itype.name;
+ r_itype.c_type_in = "MonoObject*";
+ r_itype.c_type_out = "MonoObject*";
+ r_itype.cs_type = r_itype.proxy_name;
+ r_itype.im_type_in = r_itype.proxy_name;
+ r_itype.im_type_out = r_itype.proxy_name;
+ }
+
+ TypeInterface() {
+
+ api_type = ClassDB::API_NONE;
+
+ is_object_type = false;
+ is_singleton = false;
+ is_reference = false;
+ is_instantiable = false;
+
+ memory_own = false;
+ requires_collections = false;
+
+ c_arg_in = "%s";
+
+ class_doc = NULL;
+ }
+ };
+
+ struct InternalCall {
+ String name;
+ 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;
+
+ InternalCall() {}
+
+ InternalCall(const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
+ name = p_name;
+ im_type_out = p_im_type_out;
+ im_sig = p_im_sig;
+ unique_sig = p_unique_sig;
+ editor_only = false;
+ }
+
+ InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
+ name = p_name;
+ im_type_out = p_im_type_out;
+ im_sig = p_im_sig;
+ unique_sig = p_unique_sig;
+ editor_only = api_type == ClassDB::API_EDITOR;
+ }
+
+ inline bool operator==(const InternalCall &p_a) const {
+ return p_a.unique_sig == unique_sig;
+ }
+ };
+
+ static bool verbose_output;
+
+ Map<String, TypeInterface> placeholder_types;
+ Map<String, TypeInterface> builtin_types;
+ Map<String, TypeInterface> obj_types;
+
+ Map<String, String> extra_members;
+
+ List<InternalCall> method_icalls;
+ Map<const MethodInterface *, const InternalCall *> method_icalls_map;
+
+ List<const InternalCall *> generated_icall_funcs;
+
+ List<InternalCall> core_custom_icalls;
+ List<InternalCall> editor_custom_icalls;
+
+ const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) {
+
+ const List<InternalCall>::Element *it = p_list.front();
+ while (it) {
+ if (it->get().name == p_name) return it;
+ it = it->next();
+ }
+ return NULL;
+ }
+
+ inline String get_unique_sig(const TypeInterface &p_type) {
+ if (p_type.is_reference)
+ return "Ref";
+ else if (p_type.is_object_type)
+ return "Obj";
+
+ return p_type.name;
+ }
+
+ void _generate_header_icalls();
+ void _generate_method_icalls(const TypeInterface &p_itype);
+
+ const TypeInterface *_get_type_by_name_or_null(const String &p_name);
+ const TypeInterface *_get_type_by_name_or_placeholder(const String &p_name);
+
+ void _default_argument_from_variant(const Variant &p_var, ArgumentInterface &r_iarg);
+ void _populate_builtin_type(TypeInterface &r_type, Variant::Type vtype);
+
+ void _populate_object_type_interfaces();
+ void _populate_builtin_type_interfaces();
+
+ Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);
+
+ Error _generate_cs_property(const TypeInterface &p_itype, const DocData::PropertyDoc &p_prop_doc, List<String> &p_output);
+ Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, List<String> &p_output);
+
+ Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, List<String> &p_output);
+
+ Error _save_file(const String &path, const List<String> &content);
+
+ BindingsGenerator();
+
+ BindingsGenerator(const BindingsGenerator &);
+ BindingsGenerator &operator=(const BindingsGenerator &);
+
+public:
+ Error generate_cs_core_project(const String &p_output_dir, bool p_verbose_output = true);
+ Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true);
+ Error generate_glue(const String &p_output_dir);
+
+ static BindingsGenerator &get_singleton() {
+ static BindingsGenerator singleton;
+ return singleton;
+ }
+
+ static void handle_cmdline_args(const List<String> &p_cmdline_args);
+};
+
+#endif
+
+#endif // BINDINGS_GENERATOR_H
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
new file mode 100644
index 0000000000..bde5f0fd0b
--- /dev/null
+++ b/modules/mono/editor/csharp_project.cpp
@@ -0,0 +1,120 @@
+/*************************************************************************/
+/* csharp_project.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "csharp_project.h"
+
+#include "os/os.h"
+#include "project_settings.h"
+
+#include "../mono_gd/gd_mono_class.h"
+#include "../mono_gd/gd_mono_marshal.h"
+
+namespace CSharpProject {
+
+String generate_core_api_project(const String &p_dir, const Vector<String> &p_files) {
+
+ _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+
+ GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
+
+ Variant dir = p_dir;
+ Variant compile_items = p_files;
+ const Variant *args[2] = { &dir, &compile_items };
+ MonoObject *ex = NULL;
+ MonoObject *ret = klass->get_method("GenCoreApiProject", 2)->invoke(NULL, args, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL_V(String());
+ }
+
+ return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
+}
+
+String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files) {
+
+ _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+
+ GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
+
+ Variant dir = p_dir;
+ Variant core_dll_path = p_core_dll_path;
+ Variant compile_items = p_files;
+ const Variant *args[3] = { &dir, &core_dll_path, &compile_items };
+ MonoObject *ex = NULL;
+ MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL_V(String());
+ }
+
+ return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
+}
+
+String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files) {
+
+ _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+
+ GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
+
+ Variant dir = p_dir;
+ Variant name = p_name;
+ Variant compile_items = p_files;
+ const Variant *args[3] = { &dir, &name, &compile_items };
+ MonoObject *ex = NULL;
+ MonoObject *ret = klass->get_method("GenGameProject", 3)->invoke(NULL, args, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL_V(String());
+ }
+
+ return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : "";
+}
+
+void add_item(const String &p_project_path, const String &p_item_type, const String &p_include) {
+
+ _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+
+ GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
+
+ Variant project_path = p_project_path;
+ Variant item_type = p_item_type;
+ Variant include = p_include;
+ const Variant *args[3] = { &project_path, &item_type, &include };
+ MonoObject *ex = NULL;
+ klass->get_method("AddItemToProjectChecked", 3)->invoke(NULL, args, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL();
+ }
+}
+} // CSharpProject
diff --git a/modules/mono/editor/csharp_project.h b/modules/mono/editor/csharp_project.h
new file mode 100644
index 0000000000..4832d2251e
--- /dev/null
+++ b/modules/mono/editor/csharp_project.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* csharp_project.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CSHARP_PROJECT_H
+#define CSHARP_PROJECT_H
+
+#include "ustring.h"
+
+namespace CSharpProject {
+
+String generate_core_api_project(const String &p_dir, const Vector<String> &p_files = Vector<String>());
+String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files = Vector<String>());
+String generate_game_project(const String &p_dir, const String &p_name, const Vector<String> &p_files = Vector<String>());
+
+void add_item(const String &p_project_path, const String &p_item_type, const String &p_include);
+}
+
+#endif // CSHARP_PROJECT_H
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
new file mode 100644
index 0000000000..a26f36d64f
--- /dev/null
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -0,0 +1,515 @@
+/*************************************************************************/
+/* godotsharp_builds.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "godotsharp_builds.h"
+
+#include "main/main.h"
+
+#include "../godotsharp_dirs.h"
+#include "../mono_gd/gd_mono.h"
+#include "../mono_gd/gd_mono_class.h"
+#include "../mono_gd/gd_mono_marshal.h"
+#include "../utils/path_utils.h"
+#include "bindings_generator.h"
+#include "godotsharp_editor.h"
+
+void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString *p_config, int p_exit_code) {
+
+ String solution = GDMonoMarshal::mono_string_to_godot(p_solution);
+ String config = GDMonoMarshal::mono_string_to_godot(p_config);
+ GodotSharpBuilds::get_singleton()->build_exit_callback(MonoBuildInfo(solution, config), p_exit_code);
+}
+
+#ifdef UNIX_ENABLED
+String _find_build_engine_on_unix(const String &p_name) {
+ String ret = path_which(p_name);
+
+ if (ret.length())
+ return ret;
+
+ String ret_fallback = path_which(p_name + ".exe");
+ if (ret_fallback.length())
+ return ret_fallback;
+
+ const char *locations[] = {
+#ifdef OSX_ENABLED
+ "/Library/Frameworks/Mono.framework/Versions/Current/bin/",
+#endif
+ "/opt/novell/mono/bin/"
+ };
+
+ for (int i = 0; i < sizeof(locations) / sizeof(const char *); i++) {
+ String hint_path = locations[i] + p_name;
+
+ if (FileAccess::exists(hint_path)) {
+ return hint_path;
+ }
+ }
+
+ return String();
+}
+#endif
+
+void godot_icall_BuildInstance_get_MSBuildInfo(MonoString **r_msbuild_path, MonoString **r_framework_path) {
+
+ GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool")));
+
+#if defined(WINDOWS_ENABLED)
+ switch (build_tool) {
+ case GodotSharpBuilds::MSBUILD: {
+ static String msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path();
+
+ if (msbuild_tools_path.length()) {
+ if (!msbuild_tools_path.ends_with("\\"))
+ msbuild_tools_path += "\\";
+
+ // FrameworkPathOverride
+ const MonoRegInfo &mono_reg_info = GDMono::get_singleton()->get_mono_reg_info();
+ if (mono_reg_info.assembly_dir.length()) {
+ *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
+
+ String framework_path = path_join(mono_reg_info.assembly_dir, "mono", "4.5");
+ *r_framework_path = GDMonoMarshal::mono_string_from_godot(framework_path);
+ } else {
+ ERR_PRINT("Cannot find Mono's assemblies directory in the registry");
+ }
+
+ return;
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Cannot find System's MSBuild. Trying with Mono's...\n");
+ } // fall through
+ case GodotSharpBuilds::MSBUILD_MONO: {
+ String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat");
+
+ if (!FileAccess::exists(msbuild_path)) {
+ WARN_PRINTS("Cannot find msbuild ('mono/builds/build_tool'). Tried with path: " + msbuild_path);
+ }
+
+ *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(msbuild_path);
+
+ return;
+ } break;
+ default:
+ ERR_EXPLAIN("You don't deserve to live");
+ CRASH_NOW();
+ }
+#elif defined(UNIX_ENABLED)
+ static String msbuild_path = _find_build_engine_on_unix("msbuild");
+ static String xbuild_path = _find_build_engine_on_unix("xbuild");
+
+ if (build_tool != GodotSharpBuilds::XBUILD) {
+ if (msbuild_path.empty()) {
+ WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool').");
+ return;
+ }
+ } else {
+ if (xbuild_path.empty()) {
+ WARN_PRINT("Cannot find xbuild ('mono/builds/build_tool').");
+ return;
+ }
+ }
+
+ *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path);
+
+ return;
+#else
+ ERR_PRINT("Not implemented on this platform");
+ return;
+#endif
+}
+
+void GodotSharpBuilds::_register_internal_calls() {
+
+ mono_add_internal_call("GodotSharpTools.Build.BuildSystem::godot_icall_BuildInstance_ExitCallback", (void *)godot_icall_BuildInstance_ExitCallback);
+ mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildInfo", (void *)godot_icall_BuildInstance_get_MSBuildInfo);
+}
+
+void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
+
+ GodotSharpEditor::get_singleton()->show_error_dialog(p_message, "Build error");
+ MonoBottomPanel::get_singleton()->show_build_tab();
+}
+
+bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config) {
+
+ String api_sln_file = p_api_sln_dir.plus_file(p_name + ".sln");
+ String api_assembly_dir = p_api_sln_dir.plus_file("bin").plus_file(p_config);
+ String api_assembly_file = api_assembly_dir.plus_file(p_name + ".dll");
+
+ if (!FileAccess::exists(api_assembly_file)) {
+ MonoBuildInfo api_build_info(api_sln_file, p_config);
+ api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
+
+ if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
+ show_build_error_dialog("Failed to build " + p_name + " solution.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name) {
+
+ String assembly_file = p_assembly_name + ".dll";
+ String assembly_src = p_src_dir.plus_file(assembly_file);
+ String assembly_dst = p_dst_dir.plus_file(assembly_file);
+
+ if (!FileAccess::exists(assembly_dst) || FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst)) {
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ String xml_file = p_assembly_name + ".xml";
+ if (da->copy(p_src_dir.plus_file(xml_file), p_dst_dir.plus_file(xml_file)) != OK)
+ WARN_PRINTS("Failed to copy " + xml_file);
+
+ String pdb_file = p_assembly_name + ".pdb";
+ if (da->copy(p_src_dir.plus_file(pdb_file), p_dst_dir.plus_file(pdb_file)) != OK)
+ WARN_PRINTS("Failed to copy " + pdb_file);
+
+ Error err = da->copy(assembly_src, assembly_dst);
+
+ memdelete(da);
+
+ if (err != OK) {
+ show_build_error_dialog("Failed to copy " API_ASSEMBLY_NAME ".dll");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool GodotSharpBuilds::make_api_sln(GodotSharpBuilds::APIType p_api_type) {
+
+ String api_name = p_api_type == API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
+ String api_build_config = "Release";
+
+ EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 4);
+
+ pr.step("Generating " + api_name + " solution");
+
+ uint64_t core_hash = GDMono::get_singleton()->get_api_core_hash();
+ uint64_t editor_hash = GDMono::get_singleton()->get_api_editor_hash();
+
+ String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(API_ASSEMBLY_NAME "_" + itos(core_hash));
+ String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir().plus_file(EDITOR_API_ASSEMBLY_NAME "_" + itos(editor_hash));
+
+ String api_sln_dir = p_api_type == API_CORE ? core_api_sln_dir : editor_api_sln_dir;
+ String api_sln_file = api_sln_dir.plus_file(api_name + ".sln");
+
+ if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
+ String core_api_assembly;
+
+ if (p_api_type == API_EDITOR) {
+ core_api_assembly = core_api_sln_dir.plus_file("bin")
+ .plus_file(api_build_config)
+ .plus_file(API_ASSEMBLY_NAME ".dll");
+ }
+
+#ifndef DEBUG_METHODS_ENABLED
+#error "How am I supposed to generate the bindings?"
+#endif
+
+ BindingsGenerator &gen = BindingsGenerator::get_singleton();
+ bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
+
+ Error err = p_api_type == API_CORE ?
+ gen.generate_cs_core_project(api_sln_dir, gen_verbose) :
+ gen.generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
+
+ if (err != OK) {
+ show_build_error_dialog("Failed to generate " + api_name + " solution. Error: " + itos(err));
+ return false;
+ }
+ }
+
+ pr.step("Building " + api_name + " solution");
+
+ if (!GodotSharpBuilds::build_api_sln(api_name, api_sln_dir, api_build_config))
+ return false;
+
+ pr.step("Copying " + api_name + " assembly");
+
+ String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
+
+ // Create assemblies directory if needed
+ if (!DirAccess::exists(res_assemblies_dir)) {
+ DirAccess *da = DirAccess::create_for_path(res_assemblies_dir);
+ Error err = da->make_dir_recursive(res_assemblies_dir);
+ memdelete(da);
+
+ if (err != OK) {
+ show_build_error_dialog("Failed to create assemblies directory. Error: " + itos(err));
+ return false;
+ }
+ }
+
+ // Copy the built assembly to the assemblies directory
+ String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config);
+ if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name))
+ return false;
+
+ pr.step("Done");
+
+ return true;
+}
+
+bool GodotSharpBuilds::build_project_blocking() {
+
+ if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
+ return true; // No solution to build
+
+ if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE))
+ return false;
+
+ if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR))
+ return false;
+
+ EditorProgress pr("mono_project_debug_build", "Building project solution...", 2);
+
+ pr.step("Building project solution");
+
+ MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), "Tools");
+ if (!GodotSharpBuilds::get_singleton()->build(build_info)) {
+ GodotSharpBuilds::show_build_error_dialog("Failed to build project solution");
+ return false;
+ }
+
+ pr.step("Done");
+
+ return true;
+}
+
+GodotSharpBuilds *GodotSharpBuilds::singleton = NULL;
+
+void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) {
+
+ BuildProcess *match = builds.getptr(p_build_info);
+ ERR_FAIL_COND(!match);
+
+ BuildProcess &bp = *match;
+ bp.on_exit(p_exit_code);
+}
+
+void GodotSharpBuilds::restart_build(MonoBuildTab *p_build_tab) {
+}
+
+void GodotSharpBuilds::stop_build(MonoBuildTab *p_build_tab) {
+}
+
+bool GodotSharpBuilds::build(const MonoBuildInfo &p_build_info) {
+
+ BuildProcess *match = builds.getptr(p_build_info);
+
+ if (match) {
+ BuildProcess &bp = *match;
+ bp.start(true);
+ return bp.exit_code == 0;
+ } else {
+ BuildProcess bp = BuildProcess(p_build_info);
+ bp.start(true);
+ builds.set(p_build_info, bp);
+ return bp.exit_code == 0;
+ }
+}
+
+bool GodotSharpBuilds::build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) {
+
+ BuildProcess *match = builds.getptr(p_build_info);
+
+ if (match) {
+ BuildProcess &bp = *match;
+ bp.start();
+ return !bp.exited; // failed to start
+ } else {
+ BuildProcess bp = BuildProcess(p_build_info, p_callback);
+ bp.start();
+ builds.set(p_build_info, bp);
+ return !bp.exited; // failed to start
+ }
+}
+
+GodotSharpBuilds::GodotSharpBuilds() {
+
+ singleton = this;
+
+ EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::build_project_blocking);
+
+ // Build tool settings
+ EditorSettings *ed_settings = EditorSettings::get_singleton();
+ if (!ed_settings->has_setting("mono/builds/build_tool")) {
+ ed_settings->set_setting("mono/builds/build_tool",
+#ifdef WINDOWS_ENABLED
+ // TODO: Default to MSBUILD_MONO if its csc.exe issue is fixed in the installed mono version
+ MSBUILD
+#else
+ MSBUILD_MONO
+#endif
+ );
+ }
+ ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM,
+#ifdef WINDOWS_ENABLED
+ "MSBuild (Mono),MSBuild (System)"
+#else
+ "MSBuild (Mono),xbuild (Deprecated)"
+#endif
+ ));
+}
+
+GodotSharpBuilds::~GodotSharpBuilds() {
+
+ singleton = NULL;
+}
+
+void GodotSharpBuilds::BuildProcess::on_exit(int p_exit_code) {
+
+ exited = true;
+ exit_code = p_exit_code;
+ build_tab->on_build_exit(p_exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
+ build_instance.unref();
+
+ if (exit_callback)
+ exit_callback(exit_code);
+}
+
+void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
+
+ _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+
+ exit_code = -1;
+
+ String logs_dir = GodotSharpDirs::get_build_logs_dir().plus_file(build_info.solution.md5_text() + "_" + build_info.configuration);
+
+ if (build_tab) {
+ build_tab->on_build_start();
+ } else {
+ build_tab = memnew(MonoBuildTab(build_info, logs_dir));
+ MonoBottomPanel::get_singleton()->add_build_tab(build_tab);
+ }
+
+ if (p_blocking) {
+ // Required in order to update the build tasks list
+ Main::iteration();
+ }
+
+ if (!exited) {
+ exited = true;
+ String message = "Tried to start build process, but it is already running";
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
+ ERR_FAIL();
+ }
+
+ exited = false;
+
+ // Remove old issues file
+
+ String issues_file = "msbuild_issues.csv";
+ DirAccessRef d = DirAccess::create_for_path(logs_dir);
+ if (d->file_exists(issues_file)) {
+ Error err = d->remove(issues_file);
+ if (err != OK) {
+ exited = true;
+ String file_path = ProjectSettings::get_singleton()->localize_path(logs_dir).plus_file(issues_file);
+ String message = "Cannot remove issues file: " + file_path;
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
+ ERR_FAIL();
+ }
+ }
+
+ GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Build", "BuildInstance");
+
+ MonoObject *mono_object = mono_object_new(mono_domain_get(), klass->get_raw());
+
+ // Construct
+
+ Variant solution = build_info.solution;
+ Variant config = build_info.configuration;
+
+ const Variant *ctor_args[2] = { &solution, &config };
+
+ MonoObject *ex = NULL;
+ GDMonoMethod *ctor = klass->get_method(".ctor", 2);
+ ctor->invoke(mono_object, ctor_args, &ex);
+
+ if (ex) {
+ exited = true;
+ String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
+ ERR_FAIL();
+ }
+
+ // Call Build
+
+ Variant logger_assembly = OS::get_singleton()->get_executable_path().get_base_dir().plus_file(EDITOR_TOOLS_ASSEMBLY_NAME) + ".dll";
+ Variant logger_output_dir = logs_dir;
+ Variant custom_props = build_info.custom_props;
+
+ const Variant *args[3] = { &logger_assembly, &logger_output_dir, &custom_props };
+
+ ex = NULL;
+ GDMonoMethod *build_method = klass->get_method(p_blocking ? "Build" : "BuildAsync", 3);
+ build_method->invoke(mono_object, args, &ex);
+
+ if (ex) {
+ exited = true;
+ String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(ex);
+ build_tab->on_build_exec_failed(message);
+ ERR_EXPLAIN(message);
+ ERR_FAIL();
+ }
+
+ // Build returned
+
+ if (p_blocking) {
+ exited = true;
+ exit_code = klass->get_field("exitCode")->get_int_value(mono_object);
+
+ if (exit_code != 0 && OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print(String("MSBuild finished with exit code " + itos(exit_code) + "\n").utf8());
+
+ build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
+ } else {
+ build_instance = MonoGCHandle::create_strong(mono_object);
+ exited = false;
+ }
+}
+
+GodotSharpBuilds::BuildProcess::BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) {
+
+ build_info = p_build_info;
+ build_tab = NULL;
+ exit_callback = p_callback;
+ exited = true;
+ exit_code = -1;
+}
diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h
new file mode 100644
index 0000000000..7d2f38a774
--- /dev/null
+++ b/modules/mono/editor/godotsharp_builds.h
@@ -0,0 +1,101 @@
+/*************************************************************************/
+/* godotsharp_builds.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GODOTSHARP_BUILDS_H
+#define GODOTSHARP_BUILDS_H
+
+#include "mono_bottom_panel.h"
+#include "mono_build_info.h"
+
+typedef void (*GodotSharpBuild_ExitCallback)(int);
+
+class GodotSharpBuilds {
+
+private:
+ struct BuildProcess {
+ Ref<MonoGCHandle> build_instance;
+ MonoBuildInfo build_info;
+ MonoBuildTab *build_tab;
+ GodotSharpBuild_ExitCallback exit_callback;
+ bool exited;
+ int exit_code;
+
+ void on_exit(int p_exit_code);
+ void start(bool p_blocking = false);
+
+ BuildProcess() {}
+ BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
+ };
+
+ HashMap<MonoBuildInfo, BuildProcess, MonoBuildInfo::Hasher> builds;
+
+ static GodotSharpBuilds *singleton;
+
+ friend class GDMono;
+ static void _register_internal_calls();
+
+public:
+ enum APIType {
+ API_CORE,
+ API_EDITOR
+ };
+
+ enum BuildTool {
+ MSBUILD_MONO,
+#ifdef WINDOWS_ENABLED
+ MSBUILD
+#else
+ XBUILD // Deprecated
+#endif
+ };
+
+ _FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; }
+
+ static void show_build_error_dialog(const String &p_message);
+
+ void build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code);
+
+ void restart_build(MonoBuildTab *p_build_tab);
+ void stop_build(MonoBuildTab *p_build_tab);
+
+ bool build(const MonoBuildInfo &p_build_info);
+ bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
+
+ static bool build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config);
+ static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name);
+
+ static bool make_api_sln(APIType p_api_type);
+
+ static bool build_project_blocking();
+
+ GodotSharpBuilds();
+ ~GodotSharpBuilds();
+};
+
+#endif // GODOTSHARP_BUILDS_H
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
new file mode 100644
index 0000000000..837dbfde66
--- /dev/null
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -0,0 +1,286 @@
+/*************************************************************************/
+/* godotsharp_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "godotsharp_editor.h"
+
+#include "core/os/os.h"
+#include "core/project_settings.h"
+#include "scene/gui/control.h"
+#include "scene/main/node.h"
+
+#include "../csharp_script.h"
+#include "../godotsharp_dirs.h"
+#include "../mono_gd/gd_mono.h"
+#include "../utils/path_utils.h"
+#include "bindings_generator.h"
+#include "csharp_project.h"
+#include "net_solution.h"
+
+#ifdef WINDOWS_ENABLED
+#include "../utils/mono_reg_utils.h"
+#endif
+
+GodotSharpEditor *GodotSharpEditor::singleton = NULL;
+
+bool GodotSharpEditor::_create_project_solution() {
+
+ EditorProgress pr("create_csharp_solution", "Generating solution...", 2);
+
+ pr.step("Generating C# project...");
+
+ String path = OS::get_singleton()->get_resource_dir();
+ String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
+
+ String guid = CSharpProject::generate_game_project(path, name);
+
+ if (guid.length()) {
+
+ NETSolution solution(name);
+
+ if (!solution.set_path(path)) {
+ show_error_dialog("Failed to create solution.");
+ return false;
+ }
+
+ Vector<String> extra_configs;
+ extra_configs.push_back("Tools");
+
+ solution.add_new_project(name, guid, extra_configs);
+
+ Error sln_error = solution.save();
+
+ if (sln_error != OK) {
+ show_error_dialog("Failed to save solution.");
+ return false;
+ }
+
+ if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_CORE))
+ return false;
+
+ if (!GodotSharpBuilds::make_api_sln(GodotSharpBuilds::API_EDITOR))
+ return false;
+
+ pr.step("Done");
+
+ // Here, after all calls to progress_task_step
+ call_deferred("_remove_create_sln_menu_option");
+
+ } else {
+ show_error_dialog("Failed to create C# project.");
+ }
+
+ return true;
+}
+
+void GodotSharpEditor::_remove_create_sln_menu_option() {
+
+ menu_popup->remove_item(menu_popup->get_item_index(MENU_CREATE_SLN));
+
+ if (menu_popup->get_item_count() == 0)
+ menu_button->hide();
+
+ bottom_panel_btn->show();
+}
+
+void GodotSharpEditor::_menu_option_pressed(int p_id) {
+
+ switch (p_id) {
+ case MENU_CREATE_SLN: {
+
+ _create_project_solution();
+ } break;
+ default:
+ ERR_FAIL();
+ }
+}
+
+void GodotSharpEditor::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution);
+ ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option);
+ ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed);
+}
+
+void GodotSharpEditor::show_error_dialog(const String &p_message, const String &p_title) {
+
+ error_dialog->set_title(p_title);
+ error_dialog->set_text(p_message);
+ error_dialog->popup_centered_minsize();
+}
+
+Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) {
+
+ ExternalEditor editor = ExternalEditor(int(EditorSettings::get_singleton()->get("mono/editor/external_editor")));
+
+ switch (editor) {
+ case EDITOR_CODE: {
+ List<String> args;
+ args.push_back(ProjectSettings::get_singleton()->get_resource_path());
+
+ String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path());
+
+ if (p_line >= 0) {
+ args.push_back("-g");
+ args.push_back(script_path + ":" + itos(p_line) + ":" + itos(p_col));
+ } else {
+ args.push_back(script_path);
+ }
+
+ static String program = path_which("code");
+
+ Error err = OS::get_singleton()->execute(program.length() ? program : "code", args, false);
+
+ if (err != OK) {
+ ERR_PRINT("GodotSharp: Could not execute external editor");
+ return err;
+ }
+ } break;
+ case EDITOR_MONODEVELOP: {
+ if (!monodevel_instance)
+ monodevel_instance = memnew(MonoDevelopInstance(GodotSharpDirs::get_project_sln_path()));
+
+ String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path());
+ monodevel_instance->execute(script_path);
+ } break;
+ default:
+ return ERR_UNAVAILABLE;
+ }
+
+ return OK;
+}
+
+bool GodotSharpEditor::overrides_external_editor() {
+
+ return ExternalEditor(int(EditorSettings::get_singleton()->get("mono/editor/external_editor"))) != EDITOR_NONE;
+}
+
+GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
+
+ singleton = this;
+
+ monodevel_instance = NULL;
+
+ editor = p_editor;
+
+ error_dialog = memnew(AcceptDialog);
+ editor->get_gui_base()->add_child(error_dialog);
+
+ bottom_panel_btn = editor->add_bottom_panel_item("Mono", memnew(MonoBottomPanel(editor)));
+
+ godotsharp_builds = memnew(GodotSharpBuilds);
+
+ editor->add_child(memnew(MonoReloadNode));
+
+ menu_button = memnew(MenuButton);
+ menu_button->set_text("Mono");
+ menu_popup = menu_button->get_popup();
+
+ String sln_path = GodotSharpDirs::get_project_sln_path();
+ String csproj_path = GodotSharpDirs::get_project_csproj_path();
+
+ if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
+ bottom_panel_btn->hide();
+ menu_popup->add_item("Create C# solution", MENU_CREATE_SLN);
+ }
+
+ menu_popup->connect("id_pressed", this, "_menu_option_pressed");
+
+ if (menu_popup->get_item_count() == 0)
+ menu_button->hide();
+
+ editor->get_menu_hb()->add_child(menu_button);
+
+ // External editor settings
+ EditorSettings *ed_settings = EditorSettings::get_singleton();
+ if (!ed_settings->has_setting("mono/editor/external_editor")) {
+ ed_settings->set_setting("mono/editor/external_editor", EDITOR_NONE);
+ }
+ ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio Code"));
+}
+
+GodotSharpEditor::~GodotSharpEditor() {
+
+ singleton = NULL;
+
+ memdelete(godotsharp_builds);
+
+ if (monodevel_instance) {
+ memdelete(monodevel_instance);
+ monodevel_instance = NULL;
+ }
+}
+
+MonoReloadNode *MonoReloadNode::singleton = NULL;
+
+void MonoReloadNode::_reload_timer_timeout() {
+
+ CSharpLanguage::get_singleton()->reload_assemblies_if_needed(false);
+}
+
+void MonoReloadNode::restart_reload_timer() {
+
+ reload_timer->stop();
+ reload_timer->start();
+}
+
+void MonoReloadNode::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_reload_timer_timeout"), &MonoReloadNode::_reload_timer_timeout);
+}
+
+void MonoReloadNode::_notification(int p_what) {
+ switch (p_what) {
+ case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
+ restart_reload_timer();
+ CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
+ } break;
+ default: {
+ } break;
+ };
+}
+
+MonoReloadNode::MonoReloadNode() {
+
+ singleton = this;
+
+ reload_timer = memnew(Timer);
+ add_child(reload_timer);
+ reload_timer->set_one_shot(false);
+ reload_timer->set_wait_time(EDITOR_DEF("mono/assembly_watch_interval_sec", 0.5));
+ reload_timer->connect("timeout", this, "_reload_timer_timeout");
+ reload_timer->start();
+}
+
+MonoReloadNode::~MonoReloadNode() {
+
+ singleton = NULL;
+}
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
new file mode 100644
index 0000000000..0f2c163582
--- /dev/null
+++ b/modules/mono/editor/godotsharp_editor.h
@@ -0,0 +1,109 @@
+/*************************************************************************/
+/* godotsharp_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GODOTSHARP_EDITOR_H
+#define GODOTSHARP_EDITOR_H
+
+#include "godotsharp_builds.h"
+
+#include "monodevelop_instance.h"
+
+class GodotSharpEditor : public Node {
+ GDCLASS(GodotSharpEditor, Object)
+
+ EditorNode *editor;
+
+ MenuButton *menu_button;
+ PopupMenu *menu_popup;
+
+ AcceptDialog *error_dialog;
+
+ ToolButton *bottom_panel_btn;
+
+ GodotSharpBuilds *godotsharp_builds;
+
+ MonoDevelopInstance *monodevel_instance;
+
+ bool _create_project_solution();
+
+ void _remove_create_sln_menu_option();
+
+ void _menu_option_pressed(int p_id);
+
+ static GodotSharpEditor *singleton;
+
+protected:
+ static void _bind_methods();
+
+public:
+ enum MenuOptions {
+ MENU_CREATE_SLN
+ };
+
+ enum ExternalEditor {
+ EDITOR_NONE,
+ EDITOR_MONODEVELOP,
+ EDITOR_CODE,
+ };
+
+ _FORCE_INLINE_ static GodotSharpEditor *get_singleton() { return singleton; }
+
+ void show_error_dialog(const String &p_message, const String &p_title = "Error");
+
+ Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col);
+ bool overrides_external_editor();
+
+ GodotSharpEditor(EditorNode *p_editor);
+ ~GodotSharpEditor();
+};
+
+class MonoReloadNode : public Node {
+ GDCLASS(MonoReloadNode, Node)
+
+ Timer *reload_timer;
+
+ void _reload_timer_timeout();
+
+ static MonoReloadNode *singleton;
+
+protected:
+ static void _bind_methods();
+
+ void _notification(int p_what);
+
+public:
+ _FORCE_INLINE_ static MonoReloadNode *get_singleton() { return singleton; }
+
+ void restart_reload_timer();
+
+ MonoReloadNode();
+ ~MonoReloadNode();
+};
+
+#endif // GODOTSHARP_EDITOR_H
diff --git a/modules/mono/editor/mono_bottom_panel.cpp b/modules/mono/editor/mono_bottom_panel.cpp
new file mode 100644
index 0000000000..31dc09856a
--- /dev/null
+++ b/modules/mono/editor/mono_bottom_panel.cpp
@@ -0,0 +1,458 @@
+/*************************************************************************/
+/* mono_bottom_panel.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "mono_bottom_panel.h"
+
+#include "../csharp_script.h"
+#include "godotsharp_editor.h"
+
+MonoBottomPanel *MonoBottomPanel::singleton = NULL;
+
+void MonoBottomPanel::_update_build_tabs_list() {
+
+ build_tabs_list->clear();
+
+ int current_tab = build_tabs->get_current_tab();
+
+ bool no_current_tab = current_tab < 0 || current_tab >= build_tabs->get_tab_count();
+
+ for (int i = 0; i < build_tabs->get_child_count(); i++) {
+
+ MonoBuildTab *tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(i));
+
+ if (tab) {
+ String item_name = tab->build_info.solution.get_file().get_basename();
+ item_name += " [" + tab->build_info.configuration + "]";
+
+ build_tabs_list->add_item(item_name, tab->get_icon_texture());
+
+ String item_tooltip = String("Solution: ") + tab->build_info.solution;
+ item_tooltip += String("\nConfiguration: ") + tab->build_info.configuration;
+ item_tooltip += String("\nStatus: ");
+
+ if (tab->build_exited) {
+ item_tooltip += tab->build_result == MonoBuildTab::RESULT_SUCCESS ? "Succeeded" : "Errored";
+ } else {
+ item_tooltip += "Running";
+ }
+
+ if (!tab->build_exited || !tab->build_result == MonoBuildTab::RESULT_SUCCESS) {
+ item_tooltip += "\nErrors: " + itos(tab->error_count);
+ }
+
+ item_tooltip += "\nWarnings: " + itos(tab->warning_count);
+
+ build_tabs_list->set_item_tooltip(i, item_tooltip);
+
+ if (no_current_tab || current_tab == i) {
+ build_tabs_list->select(i);
+ _build_tab_item_selected(i);
+ }
+ }
+ }
+}
+
+void MonoBottomPanel::add_build_tab(MonoBuildTab *p_build_tab) {
+
+ build_tabs->add_child(p_build_tab);
+ raise_build_tab(p_build_tab);
+}
+
+void MonoBottomPanel::raise_build_tab(MonoBuildTab *p_build_tab) {
+
+ ERR_FAIL_COND(p_build_tab->get_parent() != build_tabs);
+ build_tabs->move_child(p_build_tab, 0);
+ _update_build_tabs_list();
+}
+
+void MonoBottomPanel::show_build_tab() {
+
+ for (int i = 0; i < panel_tabs->get_tab_count(); i++) {
+ if (panel_tabs->get_tab_control(i) == panel_builds_tab) {
+ panel_tabs->set_current_tab(i);
+ editor->make_bottom_panel_item_visible(this);
+ return;
+ }
+ }
+
+ ERR_PRINT("Builds tab not found");
+}
+
+void MonoBottomPanel::_build_tab_item_selected(int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx, build_tabs->get_tab_count());
+ build_tabs->set_current_tab(p_idx);
+}
+
+void MonoBottomPanel::_build_tab_changed(int p_idx) {
+
+ if (p_idx < 0 || p_idx >= build_tabs->get_tab_count()) {
+ warnings_btn->set_visible(false);
+ errors_btn->set_visible(false);
+ } else {
+ warnings_btn->set_visible(true);
+ errors_btn->set_visible(true);
+ }
+}
+
+void MonoBottomPanel::_warnings_toggled(bool p_pressed) {
+
+ int current_tab = build_tabs->get_current_tab();
+ ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
+ MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
+ build_tab->warnings_visible = p_pressed;
+ build_tab->_update_issues_list();
+}
+
+void MonoBottomPanel::_errors_toggled(bool p_pressed) {
+
+ int current_tab = build_tabs->get_current_tab();
+ ERR_FAIL_INDEX(current_tab, build_tabs->get_tab_count());
+ MonoBuildTab *build_tab = Object::cast_to<MonoBuildTab>(build_tabs->get_child(current_tab));
+ build_tab->errors_visible = p_pressed;
+ build_tab->_update_issues_list();
+}
+
+void MonoBottomPanel::_build_project_pressed() {
+
+ GodotSharpBuilds::get_singleton()->build_project_blocking();
+
+ MonoReloadNode::get_singleton()->restart_reload_timer();
+ CSharpLanguage::get_singleton()->reload_assemblies_if_needed(true);
+}
+
+void MonoBottomPanel::_notification(int p_what) {
+
+ switch (p_what) {
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
+ panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
+ panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
+ } break;
+ }
+}
+
+void MonoBottomPanel::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_build_project_pressed"), &MonoBottomPanel::_build_project_pressed);
+ ClassDB::bind_method(D_METHOD("_warnings_toggled", "pressed"), &MonoBottomPanel::_warnings_toggled);
+ ClassDB::bind_method(D_METHOD("_errors_toggled", "pressed"), &MonoBottomPanel::_errors_toggled);
+ ClassDB::bind_method(D_METHOD("_build_tab_item_selected", "idx"), &MonoBottomPanel::_build_tab_item_selected);
+ ClassDB::bind_method(D_METHOD("_build_tab_changed", "idx"), &MonoBottomPanel::_build_tab_changed);
+}
+
+MonoBottomPanel::MonoBottomPanel(EditorNode *p_editor) {
+
+ singleton = this;
+
+ editor = p_editor;
+
+ set_v_size_flags(SIZE_EXPAND_FILL);
+ set_anchors_and_margins_preset(Control::PRESET_WIDE);
+
+ panel_tabs = memnew(TabContainer);
+ panel_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
+ panel_tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles"));
+ panel_tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles"));
+ panel_tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles"));
+ panel_tabs->set_custom_minimum_size(Size2(0, 228) * EDSCALE);
+ panel_tabs->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(panel_tabs);
+
+ { // Builds
+ panel_builds_tab = memnew(VBoxContainer);
+ panel_builds_tab->set_name(TTR("Builds"));
+ panel_builds_tab->set_h_size_flags(SIZE_EXPAND_FILL);
+ panel_tabs->add_child(panel_builds_tab);
+
+ HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
+ toolbar_hbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ panel_builds_tab->add_child(toolbar_hbc);
+
+ ToolButton *build_project_btn = memnew(ToolButton);
+ build_project_btn->set_text("Build Project");
+ build_project_btn->set_focus_mode(FOCUS_NONE);
+ build_project_btn->connect("pressed", this, "_build_project_pressed");
+ toolbar_hbc->add_child(build_project_btn);
+
+ toolbar_hbc->add_spacer();
+
+ warnings_btn = memnew(ToolButton);
+ warnings_btn->set_text("Warnings");
+ warnings_btn->set_toggle_mode(true);
+ warnings_btn->set_pressed(true);
+ warnings_btn->set_visible(false);
+ warnings_btn->set_focus_mode(FOCUS_NONE);
+ warnings_btn->connect("toggled", this, "_warnings_toggled");
+ toolbar_hbc->add_child(warnings_btn);
+
+ errors_btn = memnew(ToolButton);
+ errors_btn->set_text("Errors");
+ errors_btn->set_toggle_mode(true);
+ errors_btn->set_pressed(true);
+ errors_btn->set_visible(false);
+ errors_btn->set_focus_mode(FOCUS_NONE);
+ errors_btn->connect("toggled", this, "_errors_toggled");
+ toolbar_hbc->add_child(errors_btn);
+
+ HSplitContainer *hsc = memnew(HSplitContainer);
+ hsc->set_h_size_flags(SIZE_EXPAND_FILL);
+ hsc->set_v_size_flags(SIZE_EXPAND_FILL);
+ panel_builds_tab->add_child(hsc);
+
+ build_tabs_list = memnew(ItemList);
+ build_tabs_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ build_tabs_list->connect("item_selected", this, "_build_tab_item_selected");
+ hsc->add_child(build_tabs_list);
+
+ build_tabs = memnew(TabContainer);
+ build_tabs->set_tab_align(TabContainer::ALIGN_LEFT);
+ build_tabs->set_h_size_flags(SIZE_EXPAND_FILL);
+ build_tabs->set_tabs_visible(false);
+ build_tabs->connect("tab_changed", this, "_build_tab_changed");
+ hsc->add_child(build_tabs);
+ }
+}
+
+MonoBottomPanel::~MonoBottomPanel() {
+
+ singleton = NULL;
+}
+
+void MonoBuildTab::_load_issues_from_file(const String &p_csv_file) {
+
+ FileAccessRef f = FileAccess::open(p_csv_file, FileAccess::READ);
+
+ if (!f)
+ return;
+
+ while (!f->eof_reached()) {
+ Vector<String> csv_line = f->get_csv_line();
+
+ if (csv_line.size() == 1 && csv_line[0].empty())
+ return;
+
+ ERR_CONTINUE(csv_line.size() != 7);
+
+ BuildIssue issue;
+ issue.warning = csv_line[0] == "warning";
+ issue.file = csv_line[1];
+ issue.line = csv_line[2].to_int();
+ issue.column = csv_line[3].to_int();
+ issue.code = csv_line[4];
+ issue.message = csv_line[5];
+ issue.project_file = csv_line[6];
+
+ if (issue.warning)
+ warning_count += 1;
+ else
+ error_count += 1;
+
+ issues.push_back(issue);
+ }
+}
+
+void MonoBuildTab::_update_issues_list() {
+
+ issues_list->clear();
+
+ Ref<Texture> warning_icon = get_icon("Warning", "EditorIcons");
+ Ref<Texture> error_icon = get_icon("Error", "EditorIcons");
+
+ for (int i = 0; i < issues.size(); i++) {
+
+ const BuildIssue &issue = issues[i];
+
+ if (!(issue.warning ? warnings_visible : errors_visible))
+ continue;
+
+ String tooltip;
+ tooltip += String("Message: ") + issue.message;
+
+ if (issue.code.length()) {
+ tooltip += String("\nCode: ") + issue.code;
+ }
+
+ tooltip += String("\nType: ") + (issue.warning ? "warning" : "error");
+
+ String text;
+
+ if (issue.file.length()) {
+ String sline = String::num_int64(issue.line);
+ String scolumn = String::num_int64(issue.column);
+
+ text += issue.file + "(";
+ text += sline + ",";
+ text += scolumn + "): ";
+
+ tooltip += "\nFile: " + issue.file;
+ tooltip += "\nLine: " + sline;
+ tooltip += "\nColumn: " + scolumn;
+ }
+
+ if (issue.project_file.length()) {
+ tooltip += "\nProject: " + issue.project_file;
+ }
+
+ text += issue.message;
+
+ int line_break_idx = text.find("\n");
+ issues_list->add_item(line_break_idx == -1 ? text : text.substr(0, line_break_idx),
+ issue.warning ? warning_icon : error_icon);
+ int index = issues_list->get_item_count() - 1;
+ issues_list->set_item_tooltip(index, tooltip);
+ issues_list->set_item_metadata(index, i);
+ }
+}
+
+Ref<Texture> MonoBuildTab::get_icon_texture() const {
+
+ // FIXME these icons were removed... find something better
+
+ if (build_exited) {
+ if (build_result == RESULT_ERROR) {
+ return get_icon("DependencyChangedHl", "EditorIcons");
+ } else {
+ return get_icon("DependencyOkHl", "EditorIcons");
+ }
+ } else {
+ return get_icon("GraphTime", "EditorIcons");
+ }
+}
+
+MonoBuildInfo MonoBuildTab::get_build_info() {
+
+ return build_info;
+}
+
+void MonoBuildTab::on_build_start() {
+
+ build_exited = false;
+
+ issues.clear();
+ warning_count = 0;
+ error_count = 0;
+ _update_issues_list();
+
+ MonoBottomPanel::get_singleton()->raise_build_tab(this);
+}
+
+void MonoBuildTab::on_build_exit(BuildResult result) {
+
+ build_exited = true;
+ build_result = result;
+
+ _load_issues_from_file(logs_dir.plus_file("msbuild_issues.csv"));
+ _update_issues_list();
+
+ MonoBottomPanel::get_singleton()->raise_build_tab(this);
+}
+
+void MonoBuildTab::on_build_exec_failed(const String &p_cause) {
+
+ build_exited = true;
+ build_result = RESULT_ERROR;
+
+ issues_list->clear();
+
+ BuildIssue issue;
+ issue.message = p_cause;
+ issue.warning = false;
+
+ error_count += 1;
+ issues.push_back(issue);
+
+ _update_issues_list();
+
+ MonoBottomPanel::get_singleton()->raise_build_tab(this);
+}
+
+void MonoBuildTab::restart_build() {
+
+ ERR_FAIL_COND(!build_exited);
+ GodotSharpBuilds::get_singleton()->restart_build(this);
+}
+
+void MonoBuildTab::stop_build() {
+
+ ERR_FAIL_COND(build_exited);
+ GodotSharpBuilds::get_singleton()->stop_build(this);
+}
+
+void MonoBuildTab::_issue_activated(int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx, issues.size());
+
+ const BuildIssue &issue = issues[p_idx];
+
+ if (issue.project_file.empty() && issue.file.empty())
+ return;
+
+ String project_dir = issue.project_file.length() ? issue.project_file.get_base_dir() : build_info.solution.get_base_dir();
+
+ String file = project_dir.simplify_path().plus_file(issue.file.simplify_path());
+
+ if (!FileAccess::exists(file))
+ return;
+
+ file = ProjectSettings::get_singleton()->localize_path(file);
+
+ if (file.begins_with("res://")) {
+ Ref<Script> script = ResourceLoader::load(file, CSharpLanguage::get_singleton()->get_type());
+
+ if (script.is_valid() && ScriptEditor::get_singleton()->edit(script, issue.line, issue.column)) {
+ EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
+ }
+ }
+}
+
+void MonoBuildTab::_bind_methods() {
+
+ ClassDB::bind_method("_issue_activated", &MonoBuildTab::_issue_activated);
+}
+
+MonoBuildTab::MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir) {
+
+ build_info = p_build_info;
+ logs_dir = p_logs_dir;
+
+ build_exited = false;
+
+ issues_list = memnew(ItemList);
+ issues_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ issues_list->connect("item_activated", this, "_issue_activated");
+ add_child(issues_list);
+
+ error_count = 0;
+ warning_count = 0;
+
+ errors_visible = true;
+ warnings_visible = true;
+}
diff --git a/modules/mono/editor/mono_bottom_panel.h b/modules/mono/editor/mono_bottom_panel.h
new file mode 100644
index 0000000000..5cc4aa3240
--- /dev/null
+++ b/modules/mono/editor/mono_bottom_panel.h
@@ -0,0 +1,147 @@
+/*************************************************************************/
+/* mono_bottom_panel.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef MONO_BOTTOM_PANEL_H
+#define MONO_BOTTOM_PANEL_H
+
+#include "editor/editor_node.h"
+#include "scene/gui/control.h"
+
+#include "mono_build_info.h"
+
+class MonoBuildTab;
+
+class MonoBottomPanel : public VBoxContainer {
+
+ GDCLASS(MonoBottomPanel, VBoxContainer)
+
+ EditorNode *editor;
+
+ TabContainer *panel_tabs;
+
+ VBoxContainer *panel_builds_tab;
+
+ ItemList *build_tabs_list;
+ TabContainer *build_tabs;
+
+ Button *warnings_btn;
+ Button *errors_btn;
+
+ void _update_build_tabs_list();
+
+ void _build_tab_item_selected(int p_idx);
+ void _build_tab_changed(int p_idx);
+
+ void _warnings_toggled(bool p_pressed);
+ void _errors_toggled(bool p_pressed);
+
+ void _build_project_pressed();
+
+ static MonoBottomPanel *singleton;
+
+protected:
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+ _FORCE_INLINE_ static MonoBottomPanel *get_singleton() { return singleton; }
+
+ void add_build_tab(MonoBuildTab *p_build_tab);
+ void raise_build_tab(MonoBuildTab *p_build_tab);
+
+ void show_build_tab();
+
+ MonoBottomPanel(EditorNode *p_editor = NULL);
+ ~MonoBottomPanel();
+};
+
+class MonoBuildTab : public VBoxContainer {
+
+ GDCLASS(MonoBuildTab, VBoxContainer)
+
+public:
+ enum BuildResult {
+ RESULT_ERROR,
+ RESULT_SUCCESS
+ };
+
+ struct BuildIssue {
+ bool warning;
+ String file;
+ int line;
+ int column;
+ String code;
+ String message;
+ String project_file;
+ };
+
+private:
+ friend class MonoBottomPanel;
+
+ bool build_exited;
+ BuildResult build_result;
+
+ Vector<BuildIssue> issues;
+ ItemList *issues_list;
+
+ int error_count;
+ int warning_count;
+
+ bool errors_visible;
+ bool warnings_visible;
+
+ String logs_dir;
+
+ MonoBuildInfo build_info;
+
+ void _load_issues_from_file(const String &p_csv_file);
+ void _update_issues_list();
+
+ void _issue_activated(int p_idx);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Ref<Texture> get_icon_texture() const;
+
+ MonoBuildInfo get_build_info();
+
+ void on_build_start();
+ void on_build_exit(BuildResult result);
+ void on_build_exec_failed(const String &p_cause);
+
+ void restart_build();
+ void stop_build();
+
+ MonoBuildTab(const MonoBuildInfo &p_build_info, const String &p_logs_dir);
+};
+
+#endif // MONO_BOTTOM_PANEL_H
diff --git a/modules/mono/editor/mono_build_info.h b/modules/mono/editor/mono_build_info.h
new file mode 100644
index 0000000000..f3b3e43b6d
--- /dev/null
+++ b/modules/mono/editor/mono_build_info.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* mono_build_info.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef MONO_BUILD_INFO_H
+#define MONO_BUILD_INFO_H
+
+#include "../mono_gd/gd_mono_utils.h"
+
+struct MonoBuildInfo {
+
+ struct Hasher {
+ static _FORCE_INLINE_ uint32_t hash(const MonoBuildInfo &p_key) {
+ uint32_t hash = 0;
+
+ GDMonoUtils::hash_combine(hash, p_key.solution.hash());
+ GDMonoUtils::hash_combine(hash, p_key.configuration.hash());
+
+ return hash;
+ }
+ };
+
+ String solution;
+ String configuration;
+ Vector<String> custom_props;
+
+ MonoBuildInfo() {}
+
+ MonoBuildInfo(const String &p_solution, const String &p_config) {
+ solution = p_solution;
+ configuration = p_config;
+ }
+
+ bool operator==(const MonoBuildInfo &p_b) const {
+ return p_b.solution == solution && p_b.configuration == configuration;
+ }
+};
+
+#endif // MONO_BUILD_INFO_H
diff --git a/modules/mono/editor/monodevelop_instance.cpp b/modules/mono/editor/monodevelop_instance.cpp
new file mode 100644
index 0000000000..a34d82ffcb
--- /dev/null
+++ b/modules/mono/editor/monodevelop_instance.cpp
@@ -0,0 +1,81 @@
+/*************************************************************************/
+/* monodevelop_instance.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "monodevelop_instance.h"
+
+#include "../mono_gd/gd_mono.h"
+#include "../mono_gd/gd_mono_class.h"
+
+void MonoDevelopInstance::execute(const Vector<String> &p_files) {
+
+ ERR_FAIL_NULL(execute_method);
+ ERR_FAIL_COND(gc_handle.is_null());
+
+ MonoObject *ex = NULL;
+
+ Variant files = p_files;
+ const Variant *args[1] = { &files };
+ execute_method->invoke(gc_handle->get_target(), args, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL();
+ }
+}
+
+void MonoDevelopInstance::execute(const String &p_file) {
+
+ Vector<String> files;
+ files.push_back(p_file);
+ execute(files);
+}
+
+MonoDevelopInstance::MonoDevelopInstance(const String &p_solution) {
+
+ _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
+
+ GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Editor", "MonoDevelopInstance");
+
+ MonoObject *obj = mono_object_new(TOOLS_DOMAIN, klass->get_raw());
+
+ GDMonoMethod *ctor = klass->get_method(".ctor", 1);
+ MonoObject *ex = NULL;
+
+ Variant solution = p_solution;
+ const Variant *args[1] = { &solution };
+ ctor->invoke(obj, args, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL();
+ }
+
+ gc_handle = MonoGCHandle::create_strong(obj);
+ execute_method = klass->get_method("Execute", 1);
+}
diff --git a/modules/mono/editor/monodevelop_instance.h b/modules/mono/editor/monodevelop_instance.h
new file mode 100644
index 0000000000..9eb154eba1
--- /dev/null
+++ b/modules/mono/editor/monodevelop_instance.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* monodevelop_instance.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef MONODEVELOP_INSTANCE_H
+#define MONODEVELOP_INSTANCE_H
+
+#include "reference.h"
+
+#include "../mono_gc_handle.h"
+#include "../mono_gd/gd_mono_method.h"
+
+class MonoDevelopInstance {
+
+ Ref<MonoGCHandle> gc_handle;
+ GDMonoMethod *execute_method;
+
+public:
+ void execute(const Vector<String> &p_files);
+ void execute(const String &p_files);
+
+ MonoDevelopInstance(const String &p_solution);
+};
+
+#endif // MONODEVELOP_INSTANCE_H
diff --git a/modules/mono/editor/net_solution.cpp b/modules/mono/editor/net_solution.cpp
new file mode 100644
index 0000000000..fa60c310db
--- /dev/null
+++ b/modules/mono/editor/net_solution.cpp
@@ -0,0 +1,130 @@
+/*************************************************************************/
+/* net_solution.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "net_solution.h"
+
+#include "os/dir_access.h"
+#include "os/file_access.h"
+
+#include "../utils/path_utils.h"
+#include "../utils/string_utils.h"
+#include "csharp_project.h"
+
+#define SOLUTION_TEMPLATE \
+ "Microsoft Visual Studio Solution File, Format Version 12.00\n" \
+ "# Visual Studio 2012\n" \
+ "%0\n" \
+ "Global\n" \
+ "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n" \
+ "%1\n" \
+ "\tEndGlobalSection\n" \
+ "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n" \
+ "%2\n" \
+ "\tEndGlobalSection\n" \
+ "EndGlobal\n"
+
+#define PROJECT_DECLARATION "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"%0\", \"%1\", \"{%2}\"\nEndProject"
+
+#define SOLUTION_PLATFORMS_CONFIG "\t\%0|Any CPU = %0|Any CPU"
+
+#define PROJECT_PLATFORMS_CONFIG \
+ "\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \
+ "\t\t{%0}.%1|Any CPU.Build.0 = %1|Any CPU"
+
+void NETSolution::add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs) {
+ if (projects.has(p_name))
+ WARN_PRINT("Overriding existing project.");
+
+ ProjectInfo procinfo;
+ procinfo.guid = p_guid;
+
+ procinfo.configs.push_back("Debug");
+ procinfo.configs.push_back("Release");
+
+ for (int i = 0; i < p_extra_configs.size(); i++) {
+ procinfo.configs.push_back(p_extra_configs[i]);
+ }
+
+ projects[p_name] = procinfo;
+}
+
+Error NETSolution::save() {
+ bool dir_exists = DirAccess::exists(path);
+ ERR_EXPLAIN("The directory does not exist.");
+ ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
+
+ String projs_decl;
+ String sln_platform_cfg;
+ String proj_platform_cfg;
+
+ for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) {
+ const String &name = E->key();
+ const ProjectInfo &procinfo = E->value();
+
+ projs_decl += sformat(PROJECT_DECLARATION, name, name + ".csproj", procinfo.guid);
+
+ for (int i = 0; i < procinfo.configs.size(); i++) {
+ const String &config = procinfo.configs[i];
+
+ if (i != 0) {
+ sln_platform_cfg += "\n";
+ proj_platform_cfg += "\n";
+ }
+
+ sln_platform_cfg += sformat(SOLUTION_PLATFORMS_CONFIG, config);
+ proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, procinfo.guid, config);
+ }
+ }
+
+ String content = sformat(SOLUTION_TEMPLATE, projs_decl, sln_platform_cfg, proj_platform_cfg);
+
+ FileAccessRef file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
+ ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
+ file->store_string(content);
+ file->close();
+
+ return OK;
+}
+
+bool NETSolution::set_path(const String &p_existing_path) {
+ if (p_existing_path.is_abs_path()) {
+ path = p_existing_path;
+ } else {
+ String abspath;
+ if (!rel_path_to_abs(p_existing_path, abspath))
+ return false;
+ path = abspath;
+ }
+
+ return true;
+}
+
+NETSolution::NETSolution(const String &p_name) {
+ name = p_name;
+}
diff --git a/modules/mono/editor/net_solution.h b/modules/mono/editor/net_solution.h
new file mode 100644
index 0000000000..d7ccebb7df
--- /dev/null
+++ b/modules/mono/editor/net_solution.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* net_solution.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef NET_SOLUTION_H
+#define NET_SOLUTION_H
+
+#include "map.h"
+#include "ustring.h"
+
+struct NETSolution {
+ String name;
+
+ void add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs = Vector<String>());
+
+ Error save();
+
+ bool set_path(const String &p_existing_path);
+
+ NETSolution(const String &p_name);
+
+private:
+ struct ProjectInfo {
+ String guid;
+ Vector<String> configs;
+ };
+
+ String path;
+ Map<String, ProjectInfo> projects;
+};
+
+#endif // NET_SOLUTION_H
diff --git a/modules/mono/glue/cs_files/Basis.cs b/modules/mono/glue/cs_files/Basis.cs
new file mode 100644
index 0000000000..c50e783349
--- /dev/null
+++ b/modules/mono/glue/cs_files/Basis.cs
@@ -0,0 +1,520 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Basis : IEquatable<Basis>
+ {
+ private static readonly Basis identity = new Basis
+ (
+ new Vector3(1f, 0f, 0f),
+ new Vector3(0f, 1f, 0f),
+ new Vector3(0f, 0f, 1f)
+ );
+
+ private static readonly Basis[] orthoBases = new Basis[24]
+ {
+ new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f),
+ new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f),
+ new Basis(-1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f),
+ new Basis(0f, 1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f),
+ new Basis(1f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f),
+ new Basis(0f, 0f, 1f, 1f, 0f, 0f, 0f, 1f, 0f),
+ new Basis(-1f, 0f, 0f, 0f, 0f, 1f, 0f, 1f, 0f),
+ new Basis(0f, 0f, -1f, -1f, 0f, 0f, 0f, 1f, 0f),
+ new Basis(1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, -1f),
+ new Basis(0f, 1f, 0f, 1f, 0f, 0f, 0f, 0f, -1f),
+ new Basis(-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, -1f),
+ new Basis(0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, -1f),
+ new Basis(1f, 0f, 0f, 0f, 0f, 1f, 0f, -1f, 0f),
+ new Basis(0f, 0f, -1f, 1f, 0f, 0f, 0f, -1f, 0f),
+ new Basis(-1f, 0f, 0f, 0f, 0f, -1f, 0f, -1f, 0f),
+ new Basis(0f, 0f, 1f, -1f, 0f, 0f, 0f, -1f, 0f),
+ new Basis(0f, 0f, 1f, 0f, 1f, 0f, -1f, 0f, 0f),
+ new Basis(0f, -1f, 0f, 0f, 0f, 1f, -1f, 0f, 0f),
+ new Basis(0f, 0f, -1f, 0f, -1f, 0f, -1f, 0f, 0f),
+ new Basis(0f, 1f, 0f, 0f, 0f, -1f, -1f, 0f, 0f),
+ new Basis(0f, 0f, 1f, 0f, -1f, 0f, 1f, 0f, 0f),
+ new Basis(0f, 1f, 0f, 0f, 0f, 1f, 1f, 0f, 0f),
+ new Basis(0f, 0f, -1f, 0f, 1f, 0f, 1f, 0f, 0f),
+ new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f)
+ };
+
+ public Vector3 x;
+ public Vector3 y;
+ public Vector3 z;
+
+ public static Basis Identity
+ {
+ get { return identity; }
+ }
+
+ public Vector3 Scale
+ {
+ get
+ {
+ return new Vector3
+ (
+ new Vector3(this[0, 0], this[1, 0], this[2, 0]).length(),
+ new Vector3(this[0, 1], this[1, 1], this[2, 1]).length(),
+ new Vector3(this[0, 2], this[1, 2], this[2, 2]).length()
+ );
+ }
+ }
+
+ public Vector3 this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public float this[int index, int axis]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x[axis];
+ case 1:
+ return y[axis];
+ case 2:
+ return z[axis];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x[axis] = value;
+ return;
+ case 1:
+ y[axis] = value;
+ return;
+ case 2:
+ z[axis] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal static Basis create_from_axes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+ {
+ return new Basis
+ (
+ new Vector3(xAxis.x, yAxis.x, zAxis.x),
+ new Vector3(xAxis.y, yAxis.y, zAxis.y),
+ new Vector3(xAxis.z, yAxis.z, zAxis.z)
+ );
+ }
+
+ public float determinant()
+ {
+ return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) -
+ this[1, 0] * (this[0, 1] * this[2, 2] - this[2, 1] * this[0, 2]) +
+ this[2, 0] * (this[0, 1] * this[1, 2] - this[1, 1] * this[0, 2]);
+ }
+
+ public Vector3 get_axis(int axis)
+ {
+ return new Vector3(this[0, axis], this[1, axis], this[2, axis]);
+ }
+
+ public Vector3 get_euler()
+ {
+ Basis m = this.orthonormalized();
+
+ Vector3 euler;
+ euler.z = 0.0f;
+
+ float mxy = m.y[2];
+
+
+ if (mxy < 1.0f)
+ {
+ if (mxy > -1.0f)
+ {
+ euler.x = Mathf.asin(-mxy);
+ euler.y = Mathf.atan2(m.x[2], m.z[2]);
+ euler.z = Mathf.atan2(m.y[0], m.y[1]);
+ }
+ else
+ {
+ euler.x = Mathf.PI * 0.5f;
+ euler.y = -Mathf.atan2(-m.x[1], m.x[0]);
+ }
+ }
+ else
+ {
+ euler.x = -Mathf.PI * 0.5f;
+ euler.y = -Mathf.atan2(m.x[1], m.x[0]);
+ }
+
+ return euler;
+ }
+
+ public int get_orthogonal_index()
+ {
+ Basis orth = this;
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ float v = orth[i, j];
+
+ if (v > 0.5f)
+ v = 1.0f;
+ else if (v < -0.5f)
+ v = -1.0f;
+ else
+ v = 0f;
+
+ orth[i, j] = v;
+ }
+ }
+
+ for (int i = 0; i < 24; i++)
+ {
+ if (orthoBases[i] == orth)
+ return i;
+ }
+
+ return 0;
+ }
+
+ public Basis inverse()
+ {
+ Basis inv = this;
+
+ float[] co = new float[3]
+ {
+ inv[1, 1] * inv[2, 2] - inv[1, 2] * inv[2, 1],
+ inv[1, 2] * inv[2, 0] - inv[1, 0] * inv[2, 2],
+ inv[1, 0] * inv[2, 1] - inv[1, 1] * inv[2, 0]
+ };
+
+ float det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2];
+
+ if (det == 0)
+ {
+ return new Basis
+ (
+ float.NaN, float.NaN, float.NaN,
+ float.NaN, float.NaN, float.NaN,
+ float.NaN, float.NaN, float.NaN
+ );
+ }
+
+ float s = 1.0f / det;
+
+ inv = new Basis
+ (
+ co[0] * s,
+ inv[0, 2] * inv[2, 1] - inv[0, 1] * inv[2, 2] * s,
+ inv[0, 1] * inv[1, 2] - inv[0, 2] * inv[1, 1] * s,
+ co[1] * s,
+ inv[0, 0] * inv[2, 2] - inv[0, 2] * inv[2, 0] * s,
+ inv[0, 2] * inv[1, 0] - inv[0, 0] * inv[1, 2] * s,
+ co[2] * s,
+ inv[0, 1] * inv[2, 0] - inv[0, 0] * inv[2, 1] * s,
+ inv[0, 0] * inv[1, 1] - inv[0, 1] * inv[1, 0] * s
+ );
+
+ return inv;
+ }
+
+ public Basis orthonormalized()
+ {
+ Vector3 xAxis = get_axis(0);
+ Vector3 yAxis = get_axis(1);
+ Vector3 zAxis = get_axis(2);
+
+ xAxis.normalize();
+ yAxis = (yAxis - xAxis * (xAxis.dot(yAxis)));
+ yAxis.normalize();
+ zAxis = (zAxis - xAxis * (xAxis.dot(zAxis)) - yAxis * (yAxis.dot(zAxis)));
+ zAxis.normalize();
+
+ return Basis.create_from_axes(xAxis, yAxis, zAxis);
+ }
+
+ public Basis rotated(Vector3 axis, float phi)
+ {
+ return new Basis(axis, phi) * this;
+ }
+
+ public Basis scaled(Vector3 scale)
+ {
+ Basis m = this;
+
+ m[0, 0] *= scale.x;
+ m[0, 1] *= scale.x;
+ m[0, 2] *= scale.x;
+ m[1, 0] *= scale.y;
+ m[1, 1] *= scale.y;
+ m[1, 2] *= scale.y;
+ m[2, 0] *= scale.z;
+ m[2, 1] *= scale.z;
+ m[2, 2] *= scale.z;
+
+ return m;
+ }
+
+ public float tdotx(Vector3 with)
+ {
+ return this[0, 0] * with[0] + this[1, 0] * with[1] + this[2, 0] * with[2];
+ }
+
+ public float tdoty(Vector3 with)
+ {
+ return this[0, 1] * with[0] + this[1, 1] * with[1] + this[2, 1] * with[2];
+ }
+
+ public float tdotz(Vector3 with)
+ {
+ return this[0, 2] * with[0] + this[1, 2] * with[1] + this[2, 2] * with[2];
+ }
+
+ public Basis transposed()
+ {
+ Basis tr = this;
+
+ float temp = this[0, 1];
+ this[0, 1] = this[1, 0];
+ this[1, 0] = temp;
+
+ temp = this[0, 2];
+ this[0, 2] = this[2, 0];
+ this[2, 0] = temp;
+
+ temp = this[1, 2];
+ this[1, 2] = this[2, 1];
+ this[2, 1] = temp;
+
+ return tr;
+ }
+
+ public Vector3 xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ this[0].dot(v),
+ this[1].dot(v),
+ this[2].dot(v)
+ );
+ }
+
+ public Vector3 xform_inv(Vector3 v)
+ {
+ return new Vector3
+ (
+ (this[0, 0] * v.x) + (this[1, 0] * v.y) + (this[2, 0] * v.z),
+ (this[0, 1] * v.x) + (this[1, 1] * v.y) + (this[2, 1] * v.z),
+ (this[0, 2] * v.x) + (this[1, 2] * v.y) + (this[2, 2] * v.z)
+ );
+ }
+
+ public Quat Quat() {
+ float trace = x[0] + y[1] + z[2];
+
+ if (trace > 0.0f) {
+ float s = Mathf.sqrt(trace + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ (z[1] - y[2]) * inv_s,
+ (x[2] - z[0]) * inv_s,
+ (y[0] - x[1]) * inv_s,
+ s * 0.25f
+ );
+ } else if (x[0] > y[1] && x[0] > z[2]) {
+ float s = Mathf.sqrt(x[0] - y[1] - z[2] + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ s * 0.25f,
+ (x[1] + y[0]) * inv_s,
+ (x[2] + z[0]) * inv_s,
+ (z[1] - y[2]) * inv_s
+ );
+ } else if (y[1] > z[2]) {
+ float s = Mathf.sqrt(-x[0] + y[1] - z[2] + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ (x[1] + y[0]) * inv_s,
+ s * 0.25f,
+ (y[2] + z[1]) * inv_s,
+ (x[2] - z[0]) * inv_s
+ );
+ } else {
+ float s = Mathf.sqrt(-x[0] - y[1] + z[2] + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ (x[2] + z[0]) * inv_s,
+ (y[2] + z[1]) * inv_s,
+ s * 0.25f,
+ (y[0] - x[1]) * inv_s
+ );
+ }
+ }
+
+ public Basis(Quat quat)
+ {
+ float s = 2.0f / quat.length_squared();
+
+ float xs = quat.x * s;
+ float ys = quat.y * s;
+ float zs = quat.z * s;
+ float wx = quat.w * xs;
+ float wy = quat.w * ys;
+ float wz = quat.w * zs;
+ float xx = quat.x * xs;
+ float xy = quat.x * ys;
+ float xz = quat.x * zs;
+ float yy = quat.y * ys;
+ float yz = quat.y * zs;
+ float zz = quat.z * zs;
+
+ this.x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
+ this.y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
+ this.z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
+ }
+
+ public Basis(Vector3 axis, float phi)
+ {
+ Vector3 axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
+
+ float cosine = Mathf.cos(phi);
+ float sine = Mathf.sin(phi);
+
+ this.x = new Vector3
+ (
+ axis_sq.x + cosine * (1.0f - axis_sq.x),
+ axis.x * axis.y * (1.0f - cosine) - axis.z * sine,
+ axis.z * axis.x * (1.0f - cosine) + axis.y * sine
+ );
+
+ this.y = new Vector3
+ (
+ axis.x * axis.y * (1.0f - cosine) + axis.z * sine,
+ axis_sq.y + cosine * (1.0f - axis_sq.y),
+ axis.y * axis.z * (1.0f - cosine) - axis.x * sine
+ );
+
+ this.z = new Vector3
+ (
+ axis.z * axis.x * (1.0f - cosine) - axis.y * sine,
+ axis.y * axis.z * (1.0f - cosine) + axis.x * sine,
+ axis_sq.z + cosine * (1.0f - axis_sq.z)
+ );
+ }
+
+ public Basis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+ {
+ this.x = xAxis;
+ this.y = yAxis;
+ this.z = zAxis;
+ }
+
+ public Basis(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
+ {
+ this.x = new Vector3(xx, xy, xz);
+ this.y = new Vector3(yx, yy, yz);
+ this.z = new Vector3(zx, zy, zz);
+ }
+
+ public static Basis operator *(Basis left, Basis right)
+ {
+ return new Basis
+ (
+ right.tdotx(left[0]), right.tdoty(left[0]), right.tdotz(left[0]),
+ right.tdotx(left[1]), right.tdoty(left[1]), right.tdotz(left[1]),
+ right.tdotx(left[2]), right.tdoty(left[2]), right.tdotz(left[2])
+ );
+ }
+
+ public static bool operator ==(Basis left, Basis right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Basis left, Basis right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Basis)
+ {
+ return Equals((Basis)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Basis other)
+ {
+ return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.z.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.z.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Color.cs b/modules/mono/glue/cs_files/Color.cs
new file mode 100644
index 0000000000..0a00f83d47
--- /dev/null
+++ b/modules/mono/glue/cs_files/Color.cs
@@ -0,0 +1,590 @@
+using System;
+
+namespace Godot
+{
+ public struct Color : IEquatable<Color>
+ {
+ public float r;
+ public float g;
+ public float b;
+ public float a;
+
+ public int r8
+ {
+ get
+ {
+ return (int)(r * 255.0f);
+ }
+ }
+
+ public int g8
+ {
+ get
+ {
+ return (int)(g * 255.0f);
+ }
+ }
+
+ public int b8
+ {
+ get
+ {
+ return (int)(b * 255.0f);
+ }
+ }
+
+ public int a8
+ {
+ get
+ {
+ return (int)(a * 255.0f);
+ }
+ }
+
+ public float h
+ {
+ get
+ {
+ float max = Mathf.max(r, Mathf.max(g, b));
+ float min = Mathf.min(r, Mathf.min(g, b));
+
+ float delta = max - min;
+
+ if (delta == 0)
+ return 0;
+
+ float h;
+
+ if (r == max)
+ h = (g - b) / delta; // Between yellow & magenta
+ else if (g == max)
+ h = 2 + (b - r) / delta; // Between cyan & yellow
+ else
+ h = 4 + (r - g) / delta; // Between magenta & cyan
+
+ h /= 6.0f;
+
+ if (h < 0)
+ h += 1.0f;
+
+ return h;
+ }
+ set
+ {
+ this = from_hsv(value, s, v);
+ }
+ }
+
+ public float s
+ {
+ get
+ {
+ float max = Mathf.max(r, Mathf.max(g, b));
+ float min = Mathf.min(r, Mathf.min(g, b));
+
+ float delta = max - min;
+
+ return max != 0 ? delta / max : 0;
+ }
+ set
+ {
+ this = from_hsv(h, value, v);
+ }
+ }
+
+ public float v
+ {
+ get
+ {
+ return Mathf.max(r, Mathf.max(g, b));
+ }
+ set
+ {
+ this = from_hsv(h, s, value);
+ }
+ }
+
+ private static readonly Color black = new Color(0f, 0f, 0f, 1.0f);
+
+ public Color Black
+ {
+ get
+ {
+ return black;
+ }
+ }
+
+ public float this [int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return r;
+ case 1:
+ return g;
+ case 2:
+ return b;
+ case 3:
+ return a;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ r = value;
+ return;
+ case 1:
+ g = value;
+ return;
+ case 2:
+ b = value;
+ return;
+ case 3:
+ a = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public static void to_hsv(Color color, out float hue, out float saturation, out float value)
+ {
+ int max = Mathf.max(color.r8, Mathf.max(color.g8, color.b8));
+ int min = Mathf.min(color.r8, Mathf.min(color.g8, color.b8));
+
+ float delta = max - min;
+
+ if (delta == 0)
+ {
+ hue = 0;
+ }
+ else
+ {
+ if (color.r == max)
+ hue = (color.g - color.b) / delta; // Between yellow & magenta
+ else if (color.g == max)
+ hue = 2 + (color.b - color.r) / delta; // Between cyan & yellow
+ else
+ hue = 4 + (color.r - color.g) / delta; // Between magenta & cyan
+
+ hue /= 6.0f;
+
+ if (hue < 0)
+ hue += 1.0f;
+ }
+
+ saturation = (max == 0) ? 0 : 1f - (1f * min / max);
+ value = max / 255f;
+ }
+
+ public static Color from_hsv(float hue, float saturation, float value, float alpha = 1.0f)
+ {
+ if (saturation == 0)
+ {
+ // acp_hromatic (grey)
+ return new Color(value, value, value, alpha);
+ }
+
+ int i;
+ float f, p, q, t;
+
+ hue *= 6.0f;
+ hue %= 6f;
+ i = (int)hue;
+
+ f = hue - i;
+ p = value * (1 - saturation);
+ q = value * (1 - saturation * f);
+ t = value * (1 - saturation * (1 - f));
+
+ switch (i)
+ {
+ case 0: // Red is the dominant color
+ return new Color(value, t, p, alpha);
+ case 1: // Green is the dominant color
+ return new Color(q, value, p, alpha);
+ case 2:
+ return new Color(p, value, t, alpha);
+ case 3: // Blue is the dominant color
+ return new Color(p, q, value, alpha);
+ case 4:
+ return new Color(t, p, value, alpha);
+ default: // (5) Red is the dominant color
+ return new Color(value, p, q, alpha);
+ }
+ }
+
+ public Color blend(Color over)
+ {
+ Color res;
+
+ float sa = 1.0f - over.a;
+ res.a = a * sa + over.a;
+
+ if (res.a == 0)
+ {
+ return new Color(0, 0, 0, 0);
+ }
+ else
+ {
+ res.r = (r * a * sa + over.r * over.a) / res.a;
+ res.g = (g * a * sa + over.g * over.a) / res.a;
+ res.b = (b * a * sa + over.b * over.a) / res.a;
+ }
+
+ return res;
+ }
+
+ public Color contrasted()
+ {
+ return new Color(
+ (r + 0.5f) % 1.0f,
+ (g + 0.5f) % 1.0f,
+ (b + 0.5f) % 1.0f
+ );
+ }
+
+ public float gray()
+ {
+ return (r + g + b) / 3.0f;
+ }
+
+ public Color inverted()
+ {
+ return new Color(
+ 1.0f - r,
+ 1.0f - g,
+ 1.0f - b
+ );
+ }
+
+ public Color linear_interpolate(Color b, float t)
+ {
+ Color res = this;
+
+ res.r += (t * (b.r - this.r));
+ res.g += (t * (b.g - this.g));
+ res.b += (t * (b.b - this.b));
+ res.a += (t * (b.a - this.a));
+
+ return res;
+ }
+
+ public int to_32()
+ {
+ int c = (byte)(a * 255);
+ c <<= 8;
+ c |= (byte)(r * 255);
+ c <<= 8;
+ c |= (byte)(g * 255);
+ c <<= 8;
+ c |= (byte)(b * 255);
+
+ return c;
+ }
+
+ public int to_ARGB32()
+ {
+ int c = (byte)(a * 255);
+ c <<= 8;
+ c |= (byte)(r * 255);
+ c <<= 8;
+ c |= (byte)(g * 255);
+ c <<= 8;
+ c |= (byte)(b * 255);
+
+ return c;
+ }
+
+ public string to_html(bool include_alpha = true)
+ {
+ String txt = string.Empty;
+
+ txt += _to_hex(r);
+ txt += _to_hex(g);
+ txt += _to_hex(b);
+
+ if (include_alpha)
+ txt = _to_hex(a) + txt;
+
+ return txt;
+ }
+
+ public Color(float r, float g, float b, float a = 1.0f)
+ {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+ }
+
+ public Color(int rgba)
+ {
+ this.a = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ this.b = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ this.g = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ this.r = (rgba & 0xFF) / 255.0f;
+ }
+
+ private static float _parse_col(string str, int ofs)
+ {
+ int ig = 0;
+
+ for (int i = 0; i < 2; i++)
+ {
+ int c = str[i + ofs];
+ int v = 0;
+
+ if (c >= '0' && c <= '9')
+ {
+ v = c - '0';
+ }
+ else if (c >= 'a' && c <= 'f')
+ {
+ v = c - 'a';
+ v += 10;
+ }
+ else if (c >= 'A' && c <= 'F')
+ {
+ v = c - 'A';
+ v += 10;
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (i == 0)
+ ig += v * 16;
+ else
+ ig += v;
+ }
+
+ return ig;
+ }
+
+ private String _to_hex(float val)
+ {
+ int v = (int)Mathf.clamp(val * 255.0f, 0, 255);
+
+ string ret = string.Empty;
+
+ for (int i = 0; i < 2; i++)
+ {
+ char[] c = { (char)0, (char)0 };
+ int lv = v & 0xF;
+
+ if (lv < 10)
+ c[0] = (char)('0' + lv);
+ else
+ c[0] = (char)('a' + lv - 10);
+
+ v >>= 4;
+ ret = c + ret;
+ }
+
+ return ret;
+ }
+
+ internal static bool html_is_valid(string color)
+ {
+ if (color.Length == 0)
+ return false;
+
+ if (color[0] == '#')
+ color = color.Substring(1, color.Length - 1);
+
+ bool alpha = false;
+
+ if (color.Length == 8)
+ alpha = true;
+ else if (color.Length == 6)
+ alpha = false;
+ else
+ return false;
+
+ if (alpha)
+ {
+ if ((int)_parse_col(color, 0) < 0)
+ return false;
+ }
+
+ int from = alpha ? 2 : 0;
+
+ if ((int)_parse_col(color, from + 0) < 0)
+ return false;
+ if ((int)_parse_col(color, from + 2) < 0)
+ return false;
+ if ((int)_parse_col(color, from + 4) < 0)
+ return false;
+
+ return true;
+ }
+
+ public static Color Color8(byte r8, byte g8, byte b8, byte a8)
+ {
+ return new Color((float)r8 / 255f, (float)g8 / 255f, (float)b8 / 255f, (float)a8 / 255f);
+ }
+
+ public Color(string rgba)
+ {
+ if (rgba.Length == 0)
+ {
+ r = 0f;
+ g = 0f;
+ b = 0f;
+ a = 1.0f;
+ return;
+ }
+
+ if (rgba[0] == '#')
+ rgba = rgba.Substring(1);
+
+ bool alpha = false;
+
+ if (rgba.Length == 8)
+ {
+ alpha = true;
+ }
+ else if (rgba.Length == 6)
+ {
+ alpha = false;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
+ }
+
+ if (alpha)
+ {
+ a = _parse_col(rgba, 0);
+
+ if (a < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Alpha is " + a + " but zero or greater is expected: " + rgba);
+ }
+ else
+ {
+ a = 1.0f;
+ }
+
+ int from = alpha ? 2 : 0;
+
+ r = _parse_col(rgba, from + 0);
+
+ if (r < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Red is " + r + " but zero or greater is expected: " + rgba);
+
+ g = _parse_col(rgba, from + 2);
+
+ if (g < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Green is " + g + " but zero or greater is expected: " + rgba);
+
+ b = _parse_col(rgba, from + 4);
+
+ if (b < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Blue is " + b + " but zero or greater is expected: " + rgba);
+ }
+
+ public static bool operator ==(Color left, Color right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Color left, Color right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Color left, Color right)
+ {
+ if (left.r == right.r)
+ {
+ if (left.g == right.g)
+ {
+ if (left.b == right.b)
+ return (left.a < right.a);
+ else
+ return (left.b < right.b);
+ }
+ else
+ {
+ return left.g < right.g;
+ }
+ }
+
+ return left.r < right.r;
+ }
+
+ public static bool operator >(Color left, Color right)
+ {
+ if (left.r == right.r)
+ {
+ if (left.g == right.g)
+ {
+ if (left.b == right.b)
+ return (left.a > right.a);
+ else
+ return (left.b > right.b);
+ }
+ else
+ {
+ return left.g > right.g;
+ }
+ }
+
+ return left.r > right.r;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Color)
+ {
+ return Equals((Color)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Color other)
+ {
+ return r == other.r && g == other.g && b == other.b && a == other.a;
+ }
+
+ public override int GetHashCode()
+ {
+ return r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0},{1},{2},{3}", new object[]
+ {
+ this.r.ToString(),
+ this.g.ToString(),
+ this.b.ToString(),
+ this.a.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0},{1},{2},{3}", new object[]
+ {
+ this.r.ToString(format),
+ this.g.ToString(format),
+ this.b.ToString(format),
+ this.a.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Error.cs b/modules/mono/glue/cs_files/Error.cs
new file mode 100644
index 0000000000..3f4a92603d
--- /dev/null
+++ b/modules/mono/glue/cs_files/Error.cs
@@ -0,0 +1,48 @@
+namespace Godot
+{
+ public enum Error : int
+ {
+ OK = 0,
+ FAILED = 1,
+ ERR_UNAVAILABLE = 2,
+ ERR_UNCONFIGURED = 3,
+ ERR_UNAUTHORIZED = 4,
+ ERR_PARAMETER_RANGE_ERROR = 5,
+ ERR_OUT_OF_MEMORY = 6,
+ ERR_FILE_NOT_FOUND = 7,
+ ERR_FILE_BAD_DRIVE = 8,
+ ERR_FILE_BAD_PATH = 9,
+ ERR_FILE_NO_PERMISSION = 10,
+ ERR_FILE_ALREADY_IN_USE = 11,
+ ERR_FILE_CANT_OPEN = 12,
+ ERR_FILE_CANT_WRITE = 13,
+ ERR_FILE_CANT_READ = 14,
+ ERR_FILE_UNRECOGNIZED = 15,
+ ERR_FILE_CORRUPT = 16,
+ ERR_FILE_MISSING_DEPENDENCIES = 17,
+ ERR_FILE_EOF = 18,
+ ERR_CANT_OPEN = 19,
+ ERR_CANT_CREATE = 20,
+ ERR_PARSE_ERROR = 43,
+ ERROR_QUERY_FAILED = 21,
+ ERR_ALREADY_IN_USE = 22,
+ ERR_LOCKED = 23,
+ ERR_TIMEOUT = 24,
+ ERR_CANT_AQUIRE_RESOURCE = 28,
+ ERR_INVALID_DATA = 30,
+ ERR_INVALID_PARAMETER = 31,
+ ERR_ALREADY_EXISTS = 32,
+ ERR_DOES_NOT_EXIST = 33,
+ ERR_DATABASE_CANT_READ = 34,
+ ERR_DATABASE_CANT_WRITE = 35,
+ ERR_COMPILATION_FAILED = 36,
+ ERR_METHOD_NOT_FOUND = 37,
+ ERR_LINK_FAILED = 38,
+ ERR_SCRIPT_FAILED = 39,
+ ERR_CYCLIC_LINK = 40,
+ ERR_BUSY = 44,
+ ERR_HELP = 46,
+ ERR_BUG = 47,
+ ERR_WTF = 49
+ }
+}
diff --git a/modules/mono/glue/cs_files/ExportAttribute.cs b/modules/mono/glue/cs_files/ExportAttribute.cs
new file mode 100644
index 0000000000..dce9cc59a0
--- /dev/null
+++ b/modules/mono/glue/cs_files/ExportAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public class ExportAttribute : Attribute
+ {
+ private int hint;
+ private string hint_string;
+
+ public ExportAttribute(int hint = GD.PROPERTY_HINT_NONE, string hint_string = "")
+ {
+ this.hint = hint;
+ this.hint_string = hint_string;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs
new file mode 100644
index 0000000000..40a42d23b4
--- /dev/null
+++ b/modules/mono/glue/cs_files/GD.cs
@@ -0,0 +1,191 @@
+using System;
+
+namespace Godot
+{
+ public static class GD
+ {
+ /*{GodotGlobalConstants}*/
+
+ public static object bytes2var(byte[] bytes)
+ {
+ return NativeCalls.godot_icall_Godot_bytes2var(bytes);
+ }
+
+ public static object convert(object what, int type)
+ {
+ return NativeCalls.godot_icall_Godot_convert(what, type);
+ }
+
+ public static float db2linear(float db)
+ {
+ return (float)Math.Exp(db * 0.11512925464970228420089957273422);
+ }
+
+ public static float dectime(float value, float amount, float step)
+ {
+ float sgn = value < 0 ? -1.0f : 1.0f;
+ float val = Mathf.abs(value);
+ val -= amount * step;
+ if (val < 0.0f)
+ val = 0.0f;
+ return val * sgn;
+ }
+
+ public static FuncRef funcref(Object instance, string funcname)
+ {
+ var ret = new FuncRef();
+ ret.SetInstance(instance);
+ ret.SetFunction(funcname);
+ return ret;
+ }
+
+ public static int hash(object var)
+ {
+ return NativeCalls.godot_icall_Godot_hash(var);
+ }
+
+ public static Object instance_from_id(int instance_id)
+ {
+ return NativeCalls.godot_icall_Godot_instance_from_id(instance_id);
+ }
+
+ public static double linear2db(double linear)
+ {
+ return Math.Log(linear) * 8.6858896380650365530225783783321;
+ }
+
+ public static Resource load(string path)
+ {
+ return ResourceLoader.Load(path);
+ }
+
+ public static void print(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_print(what);
+ }
+
+ public static void print_stack()
+ {
+ print(System.Environment.StackTrace);
+ }
+
+ public static void printerr(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_printerr(what);
+ }
+
+ public static void printraw(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_printraw(what);
+ }
+
+ public static void prints(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_prints(what);
+ }
+
+ public static void printt(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_printt(what);
+ }
+
+ public static int[] range(int length)
+ {
+ int[] ret = new int[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ ret[i] = i;
+ }
+
+ return ret;
+ }
+
+ public static int[] range(int from, int to)
+ {
+ if (to < from)
+ return new int[0];
+
+ int[] ret = new int[to - from];
+
+ for (int i = from; i < to; i++)
+ {
+ ret[i - from] = i;
+ }
+
+ return ret;
+ }
+
+ public static int[] range(int from, int to, int increment)
+ {
+ if (to < from && increment > 0)
+ return new int[0];
+ if (to > from && increment < 0)
+ return new int[0];
+
+ // Calculate count
+ int count = 0;
+
+ if (increment > 0)
+ count = ((to - from - 1) / increment) + 1;
+ else
+ count = ((from - to - 1) / -increment) + 1;
+
+ int[] ret = new int[count];
+
+ if (increment > 0)
+ {
+ int idx = 0;
+ for (int i = from; i < to; i += increment)
+ {
+ ret[idx++] = i;
+ }
+ }
+ else
+ {
+ int idx = 0;
+ for (int i = from; i > to; i += increment)
+ {
+ ret[idx++] = i;
+ }
+ }
+
+ return ret;
+ }
+
+ public static void seed(int seed)
+ {
+ NativeCalls.godot_icall_Godot_seed(seed);
+ }
+
+ public static string str(params object[] what)
+ {
+ return NativeCalls.godot_icall_Godot_str(what);
+ }
+
+ public static object str2var(string str)
+ {
+ return NativeCalls.godot_icall_Godot_str2var(str);
+ }
+
+ public static bool type_exists(string type)
+ {
+ return NativeCalls.godot_icall_Godot_type_exists(type);
+ }
+
+ public static byte[] var2bytes(object var)
+ {
+ return NativeCalls.godot_icall_Godot_var2bytes(var);
+ }
+
+ public static string var2str(object var)
+ {
+ return NativeCalls.godot_icall_Godot_var2str(var);
+ }
+
+ public static WeakRef weakref(Object obj)
+ {
+ return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj));
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GodotMethodAttribute.cs b/modules/mono/glue/cs_files/GodotMethodAttribute.cs
new file mode 100644
index 0000000000..21333c8dab
--- /dev/null
+++ b/modules/mono/glue/cs_files/GodotMethodAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Method, Inherited = true)]
+ internal class GodotMethodAttribute : Attribute
+ {
+ private string methodName;
+
+ public string MethodName { get { return methodName; } }
+
+ public GodotMethodAttribute(string methodName)
+ {
+ this.methodName = methodName;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GodotSynchronizationContext.cs b/modules/mono/glue/cs_files/GodotSynchronizationContext.cs
new file mode 100644
index 0000000000..eb4d0bed1c
--- /dev/null
+++ b/modules/mono/glue/cs_files/GodotSynchronizationContext.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Godot
+{
+ public class GodotSynchronizationContext : SynchronizationContext
+ {
+ private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> queue = new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
+
+ public override void Post(SendOrPostCallback d, object state)
+ {
+ queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
+ }
+
+ public void ExecutePendingContinuations()
+ {
+ KeyValuePair<SendOrPostCallback, object> workItem;
+ while (queue.TryTake(out workItem))
+ {
+ workItem.Key(workItem.Value);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GodotTaskScheduler.cs b/modules/mono/glue/cs_files/GodotTaskScheduler.cs
new file mode 100644
index 0000000000..f587645a49
--- /dev/null
+++ b/modules/mono/glue/cs_files/GodotTaskScheduler.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Godot
+{
+ public class GodotTaskScheduler : TaskScheduler
+ {
+ private GodotSynchronizationContext Context { get; set; }
+ private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
+
+ public GodotTaskScheduler()
+ {
+ Context = new GodotSynchronizationContext();
+ }
+
+ protected sealed override void QueueTask(Task task)
+ {
+ lock (_tasks)
+ {
+ _tasks.AddLast(task);
+ }
+ }
+
+ protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
+ {
+ if (SynchronizationContext.Current != Context)
+ {
+ return false;
+ }
+
+ if (taskWasPreviouslyQueued)
+ {
+ TryDequeue(task);
+ }
+
+ return base.TryExecuteTask(task);
+ }
+
+ protected sealed override bool TryDequeue(Task task)
+ {
+ lock (_tasks)
+ {
+ return _tasks.Remove(task);
+ }
+ }
+
+ protected sealed override IEnumerable<Task> GetScheduledTasks()
+ {
+ lock (_tasks)
+ {
+ return _tasks.ToArray();
+ }
+ }
+
+ public void Activate()
+ {
+ SynchronizationContext.SetSynchronizationContext(Context);
+ ExecuteQueuedTasks();
+ Context.ExecutePendingContinuations();
+ }
+
+ private void ExecuteQueuedTasks()
+ {
+ while (true)
+ {
+ Task task;
+
+ lock (_tasks)
+ {
+ if (_tasks.Any())
+ {
+ task = _tasks.First.Value;
+ _tasks.RemoveFirst();
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (task != null)
+ {
+ if (!TryExecuteTask(task))
+ {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/IAwaitable.cs b/modules/mono/glue/cs_files/IAwaitable.cs
new file mode 100644
index 0000000000..0397957d00
--- /dev/null
+++ b/modules/mono/glue/cs_files/IAwaitable.cs
@@ -0,0 +1,12 @@
+namespace Godot
+{
+ public interface IAwaitable
+ {
+ IAwaiter GetAwaiter();
+ }
+
+ public interface IAwaitable<out TResult>
+ {
+ IAwaiter<TResult> GetAwaiter();
+ }
+}
diff --git a/modules/mono/glue/cs_files/IAwaiter.cs b/modules/mono/glue/cs_files/IAwaiter.cs
new file mode 100644
index 0000000000..73c71b5634
--- /dev/null
+++ b/modules/mono/glue/cs_files/IAwaiter.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public interface IAwaiter : INotifyCompletion
+ {
+ bool IsCompleted { get; }
+
+ void GetResult();
+ }
+
+ public interface IAwaiter<out TResult> : INotifyCompletion
+ {
+ bool IsCompleted { get; }
+
+ TResult GetResult();
+ }
+}
diff --git a/modules/mono/glue/cs_files/MarshalUtils.cs b/modules/mono/glue/cs_files/MarshalUtils.cs
new file mode 100644
index 0000000000..2bdfb95c51
--- /dev/null
+++ b/modules/mono/glue/cs_files/MarshalUtils.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+
+namespace Godot
+{
+ internal static class MarshalUtils
+ {
+ private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values)
+ {
+ Dictionary<object, object> ret = new Dictionary<object, object>();
+
+ for (int i = 0; i < keys.Length; i++)
+ {
+ ret.Add(keys[i], values[i]);
+ }
+
+ return ret;
+ }
+
+ private static void DictionaryToArrays(Dictionary<object, object> from, out object[] keysTo, out object[] valuesTo)
+ {
+ Dictionary<object, object>.KeyCollection keys = from.Keys;
+ keysTo = new object[keys.Count];
+ keys.CopyTo(keysTo, 0);
+
+ Dictionary<object, object>.ValueCollection values = from.Values;
+ valuesTo = new object[values.Count];
+ values.CopyTo(valuesTo, 0);
+ }
+
+ private static Type GetDictionaryType()
+ {
+ return typeof(Dictionary<object, object>);
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Mathf.cs b/modules/mono/glue/cs_files/Mathf.cs
new file mode 100644
index 0000000000..cb0eb1acdd
--- /dev/null
+++ b/modules/mono/glue/cs_files/Mathf.cs
@@ -0,0 +1,234 @@
+using System;
+
+namespace Godot
+{
+ public static class Mathf
+ {
+ public const float PI = 3.14159274f;
+ public const float Epsilon = 1e-06f;
+
+ private const float Deg2RadConst = 0.0174532924f;
+ private const float Rad2DegConst = 57.29578f;
+
+ public static float abs(float s)
+ {
+ return Math.Abs(s);
+ }
+
+ public static float acos(float s)
+ {
+ return (float)Math.Acos(s);
+ }
+
+ public static float asin(float s)
+ {
+ return (float)Math.Asin(s);
+ }
+
+ public static float atan(float s)
+ {
+ return (float)Math.Atan(s);
+ }
+
+ public static float atan2(float x, float y)
+ {
+ return (float)Math.Atan2(x, y);
+ }
+
+ public static float ceil(float s)
+ {
+ return (float)Math.Ceiling(s);
+ }
+
+ public static float clamp(float val, float min, float max)
+ {
+ if (val < min)
+ {
+ return min;
+ }
+ else if (val > max)
+ {
+ return max;
+ }
+
+ return val;
+ }
+
+ public static float cos(float s)
+ {
+ return (float)Math.Cos(s);
+ }
+
+ public static float cosh(float s)
+ {
+ return (float)Math.Cosh(s);
+ }
+
+ public static int decimals(float step)
+ {
+ return decimals(step);
+ }
+
+ public static int decimals(decimal step)
+ {
+ return BitConverter.GetBytes(decimal.GetBits(step)[3])[2];
+ }
+
+ public static float deg2rad(float deg)
+ {
+ return deg * Deg2RadConst;
+ }
+
+ public static float ease(float s, float curve)
+ {
+ if (s < 0f)
+ {
+ s = 0f;
+ }
+ else if (s > 1.0f)
+ {
+ s = 1.0f;
+ }
+
+ if (curve > 0f)
+ {
+ if (curve < 1.0f)
+ {
+ return 1.0f - pow(1.0f - s, 1.0f / curve);
+ }
+
+ return pow(s, curve);
+ }
+ else if (curve < 0f)
+ {
+ if (s < 0.5f)
+ {
+ return pow(s * 2.0f, -curve) * 0.5f;
+ }
+
+ return (1.0f - pow(1.0f - (s - 0.5f) * 2.0f, -curve)) * 0.5f + 0.5f;
+ }
+
+ return 0f;
+ }
+
+ public static float exp(float s)
+ {
+ return (float)Math.Exp(s);
+ }
+
+ public static float floor(float s)
+ {
+ return (float)Math.Floor(s);
+ }
+
+ public static float fposmod(float x, float y)
+ {
+ if (x >= 0f)
+ {
+ return x % y;
+ }
+ else
+ {
+ return y - (-x % y);
+ }
+ }
+
+ public static float lerp(float from, float to, float weight)
+ {
+ return from + (to - from) * clamp(weight, 0f, 1f);
+ }
+
+ public static float log(float s)
+ {
+ return (float)Math.Log(s);
+ }
+
+ public static int max(int a, int b)
+ {
+ return (a > b) ? a : b;
+ }
+
+ public static float max(float a, float b)
+ {
+ return (a > b) ? a : b;
+ }
+
+ public static int min(int a, int b)
+ {
+ return (a < b) ? a : b;
+ }
+
+ public static float min(float a, float b)
+ {
+ return (a < b) ? a : b;
+ }
+
+ public static int nearest_po2(int val)
+ {
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val++;
+ return val;
+ }
+
+ public static float pow(float x, float y)
+ {
+ return (float)Math.Pow(x, y);
+ }
+
+ public static float rad2deg(float rad)
+ {
+ return rad * Rad2DegConst;
+ }
+
+ public static float round(float s)
+ {
+ return (float)Math.Round(s);
+ }
+
+ public static float sign(float s)
+ {
+ return (s < 0f) ? -1f : 1f;
+ }
+
+ public static float sin(float s)
+ {
+ return (float)Math.Sin(s);
+ }
+
+ public static float sinh(float s)
+ {
+ return (float)Math.Sinh(s);
+ }
+
+ public static float sqrt(float s)
+ {
+ return (float)Math.Sqrt(s);
+ }
+
+ public static float stepify(float s, float step)
+ {
+ if (step != 0f)
+ {
+ s = floor(s / step + 0.5f) * step;
+ }
+
+ return s;
+ }
+
+ public static float tan(float s)
+ {
+ return (float)Math.Tan(s);
+ }
+
+ public static float tanh(float s)
+ {
+ return (float)Math.Tanh(s);
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Plane.cs b/modules/mono/glue/cs_files/Plane.cs
new file mode 100644
index 0000000000..37f70aca1e
--- /dev/null
+++ b/modules/mono/glue/cs_files/Plane.cs
@@ -0,0 +1,209 @@
+using System;
+
+namespace Godot
+{
+ public struct Plane : IEquatable<Plane>
+ {
+ Vector3 normal;
+
+ public float x
+ {
+ get
+ {
+ return normal.x;
+ }
+ set
+ {
+ normal.x = value;
+ }
+ }
+
+ public float y
+ {
+ get
+ {
+ return normal.y;
+ }
+ set
+ {
+ normal.y = value;
+ }
+ }
+
+ public float z
+ {
+ get
+ {
+ return normal.z;
+ }
+ set
+ {
+ normal.z = value;
+ }
+ }
+
+ float d;
+
+ public Vector3 Center
+ {
+ get
+ {
+ return normal * d;
+ }
+ }
+
+ public float distance_to(Vector3 point)
+ {
+ return normal.dot(point) - d;
+ }
+
+ public Vector3 get_any_point()
+ {
+ return normal * d;
+ }
+
+ public bool has_point(Vector3 point, float epsilon = Mathf.Epsilon)
+ {
+ float dist = normal.dot(point) - d;
+ return Mathf.abs(dist) <= epsilon;
+ }
+
+ public Vector3 intersect_3(Plane b, Plane c)
+ {
+ float denom = normal.cross(b.normal).dot(c.normal);
+
+ if (Mathf.abs(denom) <= Mathf.Epsilon)
+ return new Vector3();
+
+ Vector3 result = (b.normal.cross(c.normal) * this.d) +
+ (c.normal.cross(normal) * b.d) +
+ (normal.cross(b.normal) * c.d);
+
+ return result / denom;
+ }
+
+ public Vector3 intersect_ray(Vector3 from, Vector3 dir)
+ {
+ float den = normal.dot(dir);
+
+ if (Mathf.abs(den) <= Mathf.Epsilon)
+ return new Vector3();
+
+ float dist = (normal.dot(from) - d) / den;
+
+ // This is a ray, before the emiting pos (from) does not exist
+ if (dist > Mathf.Epsilon)
+ return new Vector3();
+
+ return from + dir * -dist;
+ }
+
+ public Vector3 intersect_segment(Vector3 begin, Vector3 end)
+ {
+ Vector3 segment = begin - end;
+ float den = normal.dot(segment);
+
+ if (Mathf.abs(den) <= Mathf.Epsilon)
+ return new Vector3();
+
+ float dist = (normal.dot(begin) - d) / den;
+
+ if (dist < -Mathf.Epsilon || dist > (1.0f + Mathf.Epsilon))
+ return new Vector3();
+
+ return begin + segment * -dist;
+ }
+
+ public bool is_point_over(Vector3 point)
+ {
+ return normal.dot(point) > d;
+ }
+
+ public Plane normalized()
+ {
+ float len = normal.length();
+
+ if (len == 0)
+ return new Plane(0, 0, 0, 0);
+
+ return new Plane(normal / len, d / len);
+ }
+
+ public Vector3 project(Vector3 point)
+ {
+ return point - normal * distance_to(point);
+ }
+
+ public Plane(float a, float b, float c, float d)
+ {
+ normal = new Vector3(a, b, c);
+ this.d = d;
+ }
+
+ public Plane(Vector3 normal, float d)
+ {
+ this.normal = normal;
+ this.d = d;
+ }
+
+ public Plane(Vector3 v1, Vector3 v2, Vector3 v3)
+ {
+ normal = (v1 - v3).cross(v1 - v2);
+ normal.normalize();
+ d = normal.dot(v1);
+ }
+
+ public static Plane operator -(Plane plane)
+ {
+ return new Plane(-plane.normal, -plane.d);
+ }
+
+ public static bool operator ==(Plane left, Plane right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Plane left, Plane right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Plane)
+ {
+ return Equals((Plane)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Plane other)
+ {
+ return normal == other.normal && d == other.d;
+ }
+
+ public override int GetHashCode()
+ {
+ return normal.GetHashCode() ^ d.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.normal.ToString(),
+ this.d.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.normal.ToString(format),
+ this.d.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Quat.cs b/modules/mono/glue/cs_files/Quat.cs
new file mode 100644
index 0000000000..9b4b7fb297
--- /dev/null
+++ b/modules/mono/glue/cs_files/Quat.cs
@@ -0,0 +1,328 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Quat : IEquatable<Quat>
+ {
+ private static readonly Quat identity = new Quat(0f, 0f, 0f, 1f);
+
+ public float x;
+ public float y;
+ public float z;
+ public float w;
+
+ public static Quat Identity
+ {
+ get { return identity; }
+ }
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ case 3:
+ w = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Quat cubic_slerp(Quat b, Quat preA, Quat postB, float t)
+ {
+ float t2 = (1.0f - t) * t * 2f;
+ Quat sp = slerp(b, t);
+ Quat sq = preA.slerpni(postB, t);
+ return sp.slerpni(sq, t2);
+ }
+
+ public float dot(Quat b)
+ {
+ return x * b.x + y * b.y + z * b.z + w * b.w;
+ }
+
+ public Quat inverse()
+ {
+ return new Quat(-x, -y, -z, w);
+ }
+
+ public float length()
+ {
+ return Mathf.sqrt(length_squared());
+ }
+
+ public float length_squared()
+ {
+ return dot(this);
+ }
+
+ public Quat normalized()
+ {
+ return this / length();
+ }
+
+ public void set(float x, float y, float z, float w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ public Quat slerp(Quat b, float t)
+ {
+ // Calculate cosine
+ float cosom = x * b.x + y * b.y + z * b.z + w * b.w;
+
+ float[] to1 = new float[4];
+
+ // Adjust signs if necessary
+ if (cosom < 0.0)
+ {
+ cosom = -cosom; to1[0] = -b.x;
+ to1[1] = -b.y;
+ to1[2] = -b.z;
+ to1[3] = -b.w;
+ }
+ else
+ {
+ to1[0] = b.x;
+ to1[1] = b.y;
+ to1[2] = b.z;
+ to1[3] = b.w;
+ }
+
+ float sinom, scale0, scale1;
+
+ // Calculate coefficients
+ if ((1.0 - cosom) > Mathf.Epsilon)
+ {
+ // Standard case (Slerp)
+ float omega = Mathf.acos(cosom);
+ sinom = Mathf.sin(omega);
+ scale0 = Mathf.sin((1.0f - t) * omega) / sinom;
+ scale1 = Mathf.sin(t * omega) / sinom;
+ }
+ else
+ {
+ // Quaternions are very close so we can do a linear interpolation
+ scale0 = 1.0f - t;
+ scale1 = t;
+ }
+
+ // Calculate final values
+ return new Quat
+ (
+ scale0 * x + scale1 * to1[0],
+ scale0 * y + scale1 * to1[1],
+ scale0 * z + scale1 * to1[2],
+ scale0 * w + scale1 * to1[3]
+ );
+ }
+
+ public Quat slerpni(Quat b, float t)
+ {
+ float dot = this.dot(b);
+
+ if (Mathf.abs(dot) > 0.9999f)
+ {
+ return this;
+ }
+
+ float theta = Mathf.acos(dot);
+ float sinT = 1.0f / Mathf.sin(theta);
+ float newFactor = Mathf.sin(t * theta) * sinT;
+ float invFactor = Mathf.sin((1.0f - t) * theta) * sinT;
+
+ return new Quat
+ (
+ invFactor * this.x + newFactor * b.x,
+ invFactor * this.y + newFactor * b.y,
+ invFactor * this.z + newFactor * b.z,
+ invFactor * this.w + newFactor * b.w
+ );
+ }
+
+ public Vector3 xform(Vector3 v)
+ {
+ Quat q = this * v;
+ q *= this.inverse();
+ return new Vector3(q.x, q.y, q.z);
+ }
+
+ public Quat(float x, float y, float z, float w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ public Quat(Vector3 axis, float angle)
+ {
+ float d = axis.length();
+
+ if (d == 0f)
+ {
+ x = 0f;
+ y = 0f;
+ z = 0f;
+ w = 0f;
+ }
+ else
+ {
+ float s = Mathf.sin(angle * 0.5f) / d;
+
+ x = axis.x * s;
+ y = axis.y * s;
+ z = axis.z * s;
+ w = Mathf.cos(angle * 0.5f);
+ }
+ }
+
+ public static Quat operator *(Quat left, Quat right)
+ {
+ return new Quat
+ (
+ left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y,
+ left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z,
+ left.w * right.z + left.z * right.w + left.x * right.y - left.y * right.x,
+ left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z
+ );
+ }
+
+ public static Quat operator +(Quat left, Quat right)
+ {
+ return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
+ }
+
+ public static Quat operator -(Quat left, Quat right)
+ {
+ return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
+ }
+
+ public static Quat operator -(Quat left)
+ {
+ return new Quat(-left.x, -left.y, -left.z, -left.w);
+ }
+
+ public static Quat operator *(Quat left, Vector3 right)
+ {
+ return new Quat
+ (
+ left.w * right.x + left.y * right.z - left.z * right.y,
+ left.w * right.y + left.z * right.x - left.x * right.z,
+ left.w * right.z + left.x * right.y - left.y * right.x,
+ -left.x * right.x - left.y * right.y - left.z * right.z
+ );
+ }
+
+ public static Quat operator *(Vector3 left, Quat right)
+ {
+ return new Quat
+ (
+ right.w * left.x + right.y * left.z - right.z * left.y,
+ right.w * left.y + right.z * left.x - right.x * left.z,
+ right.w * left.z + right.x * left.y - right.y * left.x,
+ -right.x * left.x - right.y * left.y - right.z * left.z
+ );
+ }
+
+ public static Quat operator *(Quat left, float right)
+ {
+ return new Quat(left.x * right, left.y * right, left.z * right, left.w * right);
+ }
+
+ public static Quat operator *(float left, Quat right)
+ {
+ return new Quat(right.x * left, right.y * left, right.z * left, right.w * left);
+ }
+
+ public static Quat operator /(Quat left, float right)
+ {
+ return left * (1.0f / right);
+ }
+
+ public static bool operator ==(Quat left, Quat right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Quat left, Quat right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector2)
+ {
+ return Equals((Vector2)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Quat other)
+ {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2}, {3})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.z.ToString(),
+ this.w.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2}, {3})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.z.ToString(format),
+ this.w.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/RPCAttributes.cs b/modules/mono/glue/cs_files/RPCAttributes.cs
new file mode 100644
index 0000000000..08841ffd76
--- /dev/null
+++ b/modules/mono/glue/cs_files/RPCAttributes.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class RemoteAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class SyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class MasterAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class SlaveAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/cs_files/Rect2.cs b/modules/mono/glue/cs_files/Rect2.cs
new file mode 100644
index 0000000000..019342134a
--- /dev/null
+++ b/modules/mono/glue/cs_files/Rect2.cs
@@ -0,0 +1,233 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Rect2 : IEquatable<Rect2>
+ {
+ private Vector2 position;
+ private Vector2 size;
+
+ public Vector2 Position
+ {
+ get { return position; }
+ set { position = value; }
+ }
+
+ public Vector2 Size
+ {
+ get { return size; }
+ set { size = value; }
+ }
+
+ public Vector2 End
+ {
+ get { return position + size; }
+ }
+
+ public float Area
+ {
+ get { return get_area(); }
+ }
+
+ public Rect2 clip(Rect2 b)
+ {
+ Rect2 newRect = b;
+
+ if (!intersects(newRect))
+ return new Rect2();
+
+ newRect.position.x = Mathf.max(b.position.x, position.x);
+ newRect.position.y = Mathf.max(b.position.y, position.y);
+
+ Vector2 bEnd = b.position + b.size;
+ Vector2 end = position + size;
+
+ newRect.size.x = Mathf.min(bEnd.x, end.x) - newRect.position.x;
+ newRect.size.y = Mathf.min(bEnd.y, end.y) - newRect.position.y;
+
+ return newRect;
+ }
+
+ public bool encloses(Rect2 b)
+ {
+ return (b.position.x >= position.x) && (b.position.y >= position.y) &&
+ ((b.position.x + b.size.x) < (position.x + size.x)) &&
+ ((b.position.y + b.size.y) < (position.y + size.y));
+ }
+
+ public Rect2 expand(Vector2 to)
+ {
+ Rect2 expanded = this;
+
+ Vector2 begin = expanded.position;
+ Vector2 end = expanded.position + expanded.size;
+
+ if (to.x < begin.x)
+ begin.x = to.x;
+ if (to.y < begin.y)
+ begin.y = to.y;
+
+ if (to.x > end.x)
+ end.x = to.x;
+ if (to.y > end.y)
+ end.y = to.y;
+
+ expanded.position = begin;
+ expanded.size = end - begin;
+
+ return expanded;
+ }
+
+ public float get_area()
+ {
+ return size.x * size.y;
+ }
+
+ public Rect2 grow(float by)
+ {
+ Rect2 g = this;
+
+ g.position.x -= by;
+ g.position.y -= by;
+ g.size.x += by * 2;
+ g.size.y += by * 2;
+
+ return g;
+ }
+
+ public Rect2 grow_individual(float left, float top, float right, float bottom)
+ {
+ Rect2 g = this;
+
+ g.position.x -= left;
+ g.position.y -= top;
+ g.size.x += left + right;
+ g.size.y += top + bottom;
+
+ return g;
+ }
+
+ public Rect2 grow_margin(int margin, float by)
+ {
+ Rect2 g = this;
+
+ g.grow_individual((GD.MARGIN_LEFT == margin) ? by : 0,
+ (GD.MARGIN_TOP == margin) ? by : 0,
+ (GD.MARGIN_RIGHT == margin) ? by : 0,
+ (GD.MARGIN_BOTTOM == margin) ? by : 0);
+
+ return g;
+ }
+
+ public bool has_no_area()
+ {
+ return size.x <= 0 || size.y <= 0;
+ }
+
+ public bool has_point(Vector2 point)
+ {
+ if (point.x < position.x)
+ return false;
+ if (point.y < position.y)
+ return false;
+
+ if (point.x >= (position.x + size.x))
+ return false;
+ if (point.y >= (position.y + size.y))
+ return false;
+
+ return true;
+ }
+
+ public bool intersects(Rect2 b)
+ {
+ if (position.x > (b.position.x + b.size.x))
+ return false;
+ if ((position.x + size.x) < b.position.x)
+ return false;
+ if (position.y > (b.position.y + b.size.y))
+ return false;
+ if ((position.y + size.y) < b.position.y)
+ return false;
+
+ return true;
+ }
+
+ public Rect2 merge(Rect2 b)
+ {
+ Rect2 newRect;
+
+ newRect.position.x = Mathf.min(b.position.x, position.x);
+ newRect.position.y = Mathf.min(b.position.y, position.y);
+
+ newRect.size.x = Mathf.max(b.position.x + b.size.x, position.x + size.x);
+ newRect.size.y = Mathf.max(b.position.y + b.size.y, position.y + size.y);
+
+ newRect.size = newRect.size - newRect.position; // Make relative again
+
+ return newRect;
+ }
+
+ public Rect2(Vector2 position, Vector2 size)
+ {
+ this.position = position;
+ this.size = size;
+ }
+
+ public Rect2(float x, float y, float width, float height)
+ {
+ this.position = new Vector2(x, y);
+ this.size = new Vector2(width, height);
+ }
+
+ public static bool operator ==(Rect2 left, Rect2 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Rect2 left, Rect2 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Rect2)
+ {
+ return Equals((Rect2)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Rect2 other)
+ {
+ return position.Equals(other.position) && size.Equals(other.size);
+ }
+
+ public override int GetHashCode()
+ {
+ return position.GetHashCode() ^ size.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.position.ToString(),
+ this.size.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.position.ToString(format),
+ this.size.ToString(format)
+ });
+ }
+ }
+} \ No newline at end of file
diff --git a/modules/mono/glue/cs_files/Rect3.cs b/modules/mono/glue/cs_files/Rect3.cs
new file mode 100644
index 0000000000..617d33e7fd
--- /dev/null
+++ b/modules/mono/glue/cs_files/Rect3.cs
@@ -0,0 +1,477 @@
+using System;
+
+// file: core/math/rect3.h
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/math/rect3.cpp
+// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+
+namespace Godot
+{
+ public struct Rect3 : IEquatable<Rect3>
+ {
+ private Vector3 position;
+ private Vector3 size;
+
+ public Vector3 Position
+ {
+ get
+ {
+ return position;
+ }
+ }
+
+ public Vector3 Size
+ {
+ get
+ {
+ return size;
+ }
+ }
+
+ public Vector3 End
+ {
+ get
+ {
+ return position + size;
+ }
+ }
+
+ public bool encloses(Rect3 with)
+ {
+ Vector3 src_min = position;
+ Vector3 src_max = position + size;
+ Vector3 dst_min = with.position;
+ Vector3 dst_max = with.position + with.size;
+
+ return ((src_min.x <= dst_min.x) &&
+ (src_max.x > dst_max.x) &&
+ (src_min.y <= dst_min.y) &&
+ (src_max.y > dst_max.y) &&
+ (src_min.z <= dst_min.z) &&
+ (src_max.z > dst_max.z));
+ }
+
+ public Rect3 expand(Vector3 to_point)
+ {
+ Vector3 begin = position;
+ Vector3 end = position + size;
+
+ if (to_point.x < begin.x)
+ begin.x = to_point.x;
+ if (to_point.y < begin.y)
+ begin.y = to_point.y;
+ if (to_point.z < begin.z)
+ begin.z = to_point.z;
+
+ if (to_point.x > end.x)
+ end.x = to_point.x;
+ if (to_point.y > end.y)
+ end.y = to_point.y;
+ if (to_point.z > end.z)
+ end.z = to_point.z;
+
+ return new Rect3(begin, end - begin);
+ }
+
+ public float get_area()
+ {
+ return size.x * size.y * size.z;
+ }
+
+ public Vector3 get_endpoint(int idx)
+ {
+ switch (idx)
+ {
+ case 0:
+ return new Vector3(position.x, position.y, position.z);
+ case 1:
+ return new Vector3(position.x, position.y, position.z + size.z);
+ case 2:
+ return new Vector3(position.x, position.y + size.y, position.z);
+ case 3:
+ return new Vector3(position.x, position.y + size.y, position.z + size.z);
+ case 4:
+ return new Vector3(position.x + size.x, position.y, position.z);
+ case 5:
+ return new Vector3(position.x + size.x, position.y, position.z + size.z);
+ case 6:
+ return new Vector3(position.x + size.x, position.y + size.y, position.z);
+ case 7:
+ return new Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
+ default:
+ throw new ArgumentOutOfRangeException(nameof(idx), String.Format("Index is {0}, but a value from 0 to 7 is expected.", idx));
+ }
+ }
+
+ public Vector3 get_longest_axis()
+ {
+ Vector3 axis = new Vector3(1f, 0f, 0f);
+ float max_size = size.x;
+
+ if (size.y > max_size)
+ {
+ axis = new Vector3(0f, 1f, 0f);
+ max_size = size.y;
+ }
+
+ if (size.z > max_size)
+ {
+ axis = new Vector3(0f, 0f, 1f);
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public Vector3.Axis get_longest_axis_index()
+ {
+ Vector3.Axis axis = Vector3.Axis.X;
+ float max_size = size.x;
+
+ if (size.y > max_size)
+ {
+ axis = Vector3.Axis.Y;
+ max_size = size.y;
+ }
+
+ if (size.z > max_size)
+ {
+ axis = Vector3.Axis.Z;
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public float get_longest_axis_size()
+ {
+ float max_size = size.x;
+
+ if (size.y > max_size)
+ max_size = size.y;
+
+ if (size.z > max_size)
+ max_size = size.z;
+
+ return max_size;
+ }
+
+ public Vector3 get_shortest_axis()
+ {
+ Vector3 axis = new Vector3(1f, 0f, 0f);
+ float max_size = size.x;
+
+ if (size.y < max_size)
+ {
+ axis = new Vector3(0f, 1f, 0f);
+ max_size = size.y;
+ }
+
+ if (size.z < max_size)
+ {
+ axis = new Vector3(0f, 0f, 1f);
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public Vector3.Axis get_shortest_axis_index()
+ {
+ Vector3.Axis axis = Vector3.Axis.X;
+ float max_size = size.x;
+
+ if (size.y < max_size)
+ {
+ axis = Vector3.Axis.Y;
+ max_size = size.y;
+ }
+
+ if (size.z < max_size)
+ {
+ axis = Vector3.Axis.Z;
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public float get_shortest_axis_size()
+ {
+ float max_size = size.x;
+
+ if (size.y < max_size)
+ max_size = size.y;
+
+ if (size.z < max_size)
+ max_size = size.z;
+
+ return max_size;
+ }
+
+ public Vector3 get_support(Vector3 dir)
+ {
+ Vector3 half_extents = size * 0.5f;
+ Vector3 ofs = position + half_extents;
+
+ return ofs + new Vector3(
+ (dir.x > 0f) ? -half_extents.x : half_extents.x,
+ (dir.y > 0f) ? -half_extents.y : half_extents.y,
+ (dir.z > 0f) ? -half_extents.z : half_extents.z);
+ }
+
+ public Rect3 grow(float by)
+ {
+ Rect3 res = this;
+
+ res.position.x -= by;
+ res.position.y -= by;
+ res.position.z -= by;
+ res.size.x += 2.0f * by;
+ res.size.y += 2.0f * by;
+ res.size.z += 2.0f * by;
+
+ return res;
+ }
+
+ public bool has_no_area()
+ {
+ return size.x <= 0f || size.y <= 0f || size.z <= 0f;
+ }
+
+ public bool has_no_surface()
+ {
+ return size.x <= 0f && size.y <= 0f && size.z <= 0f;
+ }
+
+ public bool has_point(Vector3 point)
+ {
+ if (point.x < position.x)
+ return false;
+ if (point.y < position.y)
+ return false;
+ if (point.z < position.z)
+ return false;
+ if (point.x > position.x + size.x)
+ return false;
+ if (point.y > position.y + size.y)
+ return false;
+ if (point.z > position.z + size.z)
+ return false;
+
+ return true;
+ }
+
+ public Rect3 intersection(Rect3 with)
+ {
+ Vector3 src_min = position;
+ Vector3 src_max = position + size;
+ Vector3 dst_min = with.position;
+ Vector3 dst_max = with.position + with.size;
+
+ Vector3 min, max;
+
+ if (src_min.x > dst_max.x || src_max.x < dst_min.x)
+ {
+ return new Rect3();
+ }
+ else
+ {
+ min.x = (src_min.x > dst_min.x) ? src_min.x : dst_min.x;
+ max.x = (src_max.x < dst_max.x) ? src_max.x : dst_max.x;
+ }
+
+ if (src_min.y > dst_max.y || src_max.y < dst_min.y)
+ {
+ return new Rect3();
+ }
+ else
+ {
+ min.y = (src_min.y > dst_min.y) ? src_min.y : dst_min.y;
+ max.y = (src_max.y < dst_max.y) ? src_max.y : dst_max.y;
+ }
+
+ if (src_min.z > dst_max.z || src_max.z < dst_min.z)
+ {
+ return new Rect3();
+ }
+ else
+ {
+ min.z = (src_min.z > dst_min.z) ? src_min.z : dst_min.z;
+ max.z = (src_max.z < dst_max.z) ? src_max.z : dst_max.z;
+ }
+
+ return new Rect3(min, max - min);
+ }
+
+ public bool intersects(Rect3 with)
+ {
+ if (position.x >= (with.position.x + with.size.x))
+ return false;
+ if ((position.x + size.x) <= with.position.x)
+ return false;
+ if (position.y >= (with.position.y + with.size.y))
+ return false;
+ if ((position.y + size.y) <= with.position.y)
+ return false;
+ if (position.z >= (with.position.z + with.size.z))
+ return false;
+ if ((position.z + size.z) <= with.position.z)
+ return false;
+
+ return true;
+ }
+
+ public bool intersects_plane(Plane plane)
+ {
+ Vector3[] points =
+ {
+ new Vector3(position.x, position.y, position.z),
+ new Vector3(position.x, position.y, position.z + size.z),
+ new Vector3(position.x, position.y + size.y, position.z),
+ new Vector3(position.x, position.y + size.y, position.z + size.z),
+ new Vector3(position.x + size.x, position.y, position.z),
+ new Vector3(position.x + size.x, position.y, position.z + size.z),
+ new Vector3(position.x + size.x, position.y + size.y, position.z),
+ new Vector3(position.x + size.x, position.y + size.y, position.z + size.z),
+ };
+
+ bool over = false;
+ bool under = false;
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (plane.distance_to(points[i]) > 0)
+ over = true;
+ else
+ under = true;
+ }
+
+ return under && over;
+ }
+
+ public bool intersects_segment(Vector3 from, Vector3 to)
+ {
+ float min = 0f;
+ float max = 1f;
+
+ for (int i = 0; i < 3; i++)
+ {
+ float seg_from = from[i];
+ float seg_to = to[i];
+ float box_begin = position[i];
+ float box_end = box_begin + size[i];
+ float cmin, cmax;
+
+ if (seg_from < seg_to)
+ {
+ if (seg_from > box_end || seg_to < box_begin)
+ return false;
+
+ float length = seg_to - seg_from;
+ cmin = seg_from < box_begin ? (box_begin - seg_from) / length : 0f;
+ cmax = seg_to > box_end ? (box_end - seg_from) / length : 1f;
+ }
+ else
+ {
+ if (seg_to > box_end || seg_from < box_begin)
+ return false;
+
+ float length = seg_to - seg_from;
+ cmin = seg_from > box_end ? (box_end - seg_from) / length : 0f;
+ cmax = seg_to < box_begin ? (box_begin - seg_from) / length : 1f;
+ }
+
+ if (cmin > min)
+ {
+ min = cmin;
+ }
+
+ if (cmax < max)
+ max = cmax;
+ if (max < min)
+ return false;
+ }
+
+ return true;
+ }
+
+ public Rect3 merge(Rect3 with)
+ {
+ Vector3 beg_1 = position;
+ Vector3 beg_2 = with.position;
+ Vector3 end_1 = new Vector3(size.x, size.y, size.z) + beg_1;
+ Vector3 end_2 = new Vector3(with.size.x, with.size.y, with.size.z) + beg_2;
+
+ Vector3 min = new Vector3(
+ (beg_1.x < beg_2.x) ? beg_1.x : beg_2.x,
+ (beg_1.y < beg_2.y) ? beg_1.y : beg_2.y,
+ (beg_1.z < beg_2.z) ? beg_1.z : beg_2.z
+ );
+
+ Vector3 max = new Vector3(
+ (end_1.x > end_2.x) ? end_1.x : end_2.x,
+ (end_1.y > end_2.y) ? end_1.y : end_2.y,
+ (end_1.z > end_2.z) ? end_1.z : end_2.z
+ );
+
+ return new Rect3(min, max - min);
+ }
+
+ public Rect3(Vector3 position, Vector3 size)
+ {
+ this.position = position;
+ this.size = size;
+ }
+
+ public static bool operator ==(Rect3 left, Rect3 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Rect3 left, Rect3 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Rect3)
+ {
+ return Equals((Rect3)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Rect3 other)
+ {
+ return position == other.position && size == other.size;
+ }
+
+ public override int GetHashCode()
+ {
+ return position.GetHashCode() ^ size.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.position.ToString(),
+ this.size.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.position.ToString(format),
+ this.size.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/SignalAwaiter.cs b/modules/mono/glue/cs_files/SignalAwaiter.cs
new file mode 100644
index 0000000000..19ccc26e79
--- /dev/null
+++ b/modules/mono/glue/cs_files/SignalAwaiter.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace Godot
+{
+ public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]>
+ {
+ private bool completed = false;
+ private object[] result = null;
+ private Action action = null;
+
+ public SignalAwaiter(Godot.Object source, string signal, Godot.Object target)
+ {
+ NativeCalls.godot_icall_Object_connect_signal_awaiter(
+ Godot.Object.GetPtr(source),
+ signal, Godot.Object.GetPtr(target), this
+ );
+ }
+
+ public bool IsCompleted
+ {
+ get
+ {
+ return completed;
+ }
+ }
+
+ public void OnCompleted(Action action)
+ {
+ this.action = action;
+ }
+
+ public object[] GetResult()
+ {
+ return result;
+ }
+
+ public IAwaiter<object[]> GetAwaiter()
+ {
+ return this;
+ }
+
+ internal void SignalCallback(object[] args)
+ {
+ completed = true;
+ result = args;
+
+ if (action != null)
+ {
+ action();
+ }
+ }
+
+ internal void FailureCallback()
+ {
+ action = null;
+ completed = true;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/cs_files/StringExtensions.cs
new file mode 100644
index 0000000000..96041827aa
--- /dev/null
+++ b/modules/mono/glue/cs_files/StringExtensions.cs
@@ -0,0 +1,962 @@
+//using System;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Security;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Godot
+{
+ public static class StringExtensions
+ {
+ private static int get_slice_count(this string instance, string splitter)
+ {
+ if (instance.empty() || splitter.empty())
+ return 0;
+
+ int pos = 0;
+ int slices = 1;
+
+ while ((pos = instance.find(splitter, pos)) >= 0)
+ {
+ slices++;
+ pos += splitter.Length;
+ }
+
+ return slices;
+ }
+
+ private static string get_slicec(this string instance, char splitter, int slice)
+ {
+ if (!instance.empty() && slice >= 0)
+ {
+ int i = 0;
+ int prev = 0;
+ int count = 0;
+
+ while (true)
+ {
+ if (instance[i] == 0 || instance[i] == splitter)
+ {
+ if (slice == count)
+ {
+ return instance.Substring(prev, i - prev);
+ }
+ else
+ {
+ count++;
+ prev = i + 1;
+ }
+ }
+
+ i++;
+ }
+ }
+
+ return string.Empty;
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the path to the file without the extension.
+ // </summary>
+ public static string basename(this string instance)
+ {
+ int index = instance.LastIndexOf('.');
+
+ if (index > 0)
+ return instance.Substring(0, index);
+
+ return instance;
+ }
+
+ // <summary>
+ // Return true if the strings begins with the given string.
+ // </summary>
+ public static bool begins_with(this string instance, string text)
+ {
+ return instance.StartsWith(text);
+ }
+
+ // <summary>
+ // Return the bigrams (pairs of consecutive letters) of this string.
+ // </summary>
+ public static string[] bigrams(this string instance)
+ {
+ string[] b = new string[instance.Length - 1];
+
+ for (int i = 0; i < b.Length; i++)
+ {
+ b[i] = instance.Substring(i, 2);
+ }
+
+ return b;
+ }
+
+ // <summary>
+ // Return a copy of the string with special characters escaped using the C language standard.
+ // </summary>
+ public static string c_escape(this string instance)
+ {
+ StringBuilder sb = new StringBuilder(string.Copy(instance));
+
+ sb.Replace("\\", "\\\\");
+ sb.Replace("\a", "\\a");
+ sb.Replace("\b", "\\b");
+ sb.Replace("\f", "\\f");
+ sb.Replace("\n", "\\n");
+ sb.Replace("\r", "\\r");
+ sb.Replace("\t", "\\t");
+ sb.Replace("\v", "\\v");
+ sb.Replace("\'", "\\'");
+ sb.Replace("\"", "\\\"");
+ sb.Replace("?", "\\?");
+
+ return sb.ToString();
+ }
+
+ // <summary>
+ // Return a copy of the string with escaped characters replaced by their meanings according to the C language standard.
+ // </summary>
+ public static string c_unescape(this string instance)
+ {
+ StringBuilder sb = new StringBuilder(string.Copy(instance));
+
+ sb.Replace("\\a", "\a");
+ sb.Replace("\\b", "\b");
+ sb.Replace("\\f", "\f");
+ sb.Replace("\\n", "\n");
+ sb.Replace("\\r", "\r");
+ sb.Replace("\\t", "\t");
+ sb.Replace("\\v", "\v");
+ sb.Replace("\\'", "\'");
+ sb.Replace("\\\"", "\"");
+ sb.Replace("\\?", "?");
+ sb.Replace("\\\\", "\\");
+
+ return sb.ToString();
+ }
+
+ // <summary>
+ // Change the case of some letters. Replace underscores with spaces, convert all letters to lowercase then capitalize first and every letter following the space character. For [code]capitalize camelCase mixed_with_underscores[/code] it will return [code]Capitalize Camelcase Mixed With Underscores[/code].
+ // </summary>
+ public static string capitalize(this string instance)
+ {
+ string aux = instance.Replace("_", " ").ToLower();
+ string cap = string.Empty;
+
+ for (int i = 0; i < aux.get_slice_count(" "); i++)
+ {
+ string slice = aux.get_slicec(' ', i);
+ if (slice.Length > 0)
+ {
+ slice = char.ToUpper(slice[0]) + slice.Substring(1);
+ if (i > 0)
+ cap += " ";
+ cap += slice;
+ }
+ }
+
+ return cap;
+ }
+
+ // <summary>
+ // Perform a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
+ // </summary>
+ public static int casecmp_to(this string instance, string to)
+ {
+ if (instance.empty())
+ return to.empty() ? 0 : -1;
+
+ if (to.empty())
+ return 1;
+
+ int instance_idx = 0;
+ int to_idx = 0;
+
+ while (true)
+ {
+ if (to[to_idx] == 0 && instance[instance_idx] == 0)
+ return 0; // We're equal
+ else if (instance[instance_idx] == 0)
+ return -1; // If this is empty, and the other one is not, then we're less... I think?
+ else if (to[to_idx] == 0)
+ return 1; // Otherwise the other one is smaller...
+ else if (instance[instance_idx] < to[to_idx]) // More than
+ return -1;
+ else if (instance[instance_idx] > to[to_idx]) // Less than
+ return 1;
+
+ instance_idx++;
+ to_idx++;
+ }
+ }
+
+ // <summary>
+ // Return true if the string is empty.
+ // </summary>
+ public static bool empty(this string instance)
+ {
+ return string.IsNullOrEmpty(instance);
+ }
+
+ // <summary>
+ // Return true if the strings ends with the given string.
+ // </summary>
+ public static bool ends_with(this string instance, string text)
+ {
+ return instance.EndsWith(text);
+ }
+
+ // <summary>
+ // Erase [code]chars[/code] characters from the string starting from [code]pos[/code].
+ // </summary>
+ public static void erase(this StringBuilder instance, int pos, int chars)
+ {
+ instance.Remove(pos, chars);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the extension.
+ // </summary>
+ public static string extension(this string instance)
+ {
+ int pos = instance.find_last(".");
+
+ if (pos < 0)
+ return instance;
+
+ return instance.Substring(pos + 1, instance.Length);
+ }
+
+ // <summary>
+ // Find the first occurrence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int find(this string instance, string what, int from = 0)
+ {
+ return instance.IndexOf(what, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // <summary>
+ // Find the last occurrence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int find_last(this string instance, string what)
+ {
+ return instance.LastIndexOf(what, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // <summary>
+ // Find the first occurrence of a substring but search as case-insensitive, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int findn(this string instance, string what, int from = 0)
+ {
+ return instance.IndexOf(what, StringComparison.Ordinal);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the base directory.
+ // </summary>
+ public static string get_base_dir(this string instance)
+ {
+ int basepos = instance.find("://");
+
+ string rs = string.Empty;
+ string @base = string.Empty;
+
+ if (basepos != -1)
+ {
+ int end = basepos + 3;
+ rs = instance.Substring(end, instance.Length);
+ @base = instance.Substring(0, end);
+ }
+ else
+ {
+ if (instance.begins_with("/"))
+ {
+ rs = instance.Substring(1, instance.Length);
+ @base = "/";
+ }
+ else
+ {
+ rs = instance;
+ }
+ }
+
+ int sep = Mathf.max(rs.find_last("/"), rs.find_last("\\"));
+
+ if (sep == -1)
+ return @base;
+
+ return @base + rs.substr(0, sep);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the file and ignore the base directory.
+ // </summary>
+ public static string get_file(this string instance)
+ {
+ int sep = Mathf.max(instance.find_last("/"), instance.find_last("\\"));
+
+ if (sep == -1)
+ return instance;
+
+ return instance.Substring(sep + 1, instance.Length);
+ }
+
+ // <summary>
+ // Hash the string and return a 32 bits integer.
+ // </summary>
+ public static int hash(this string instance)
+ {
+ int index = 0;
+ int hashv = 5381;
+ int c;
+
+ while ((c = (int)instance[index++]) != 0)
+ hashv = ((hashv << 5) + hashv) + c; // hash * 33 + c
+
+ return hashv;
+ }
+
+ // <summary>
+ // Convert a string containing an hexadecimal number into an int.
+ // </summary>
+ public static int hex_to_int(this string instance)
+ {
+ int sign = 1;
+
+ if (instance[0] == '-')
+ {
+ sign = -1;
+ instance = instance.Substring(1);
+ }
+
+ if (!instance.StartsWith("0x"))
+ return 0;
+
+ return sign * int.Parse(instance.Substring(2), NumberStyles.HexNumber);
+ }
+
+ // <summary>
+ // Insert a substring at a given position.
+ // </summary>
+ public static string insert(this string instance, int pos, string what)
+ {
+ return instance.Insert(pos, what);
+ }
+
+ // <summary>
+ // If the string is a path to a file or directory, return true if the path is absolute.
+ // </summary>
+ public static bool is_abs_path(this string instance)
+ {
+ return System.IO.Path.IsPathRooted(instance);
+ }
+
+ // <summary>
+ // If the string is a path to a file or directory, return true if the path is relative.
+ // </summary>
+ public static bool is_rel_path(this string instance)
+ {
+ return !System.IO.Path.IsPathRooted(instance);
+ }
+
+ // <summary>
+ // Check whether this string is a subsequence of the given string.
+ // </summary>
+ public static bool is_subsequence_of(this string instance, string text, bool case_insensitive)
+ {
+ int len = instance.Length;
+
+ if (len == 0)
+ return true; // Technically an empty string is subsequence of any string
+
+ if (len > text.Length)
+ return false;
+
+ int src = 0;
+ int tgt = 0;
+
+ while (instance[src] != 0 && text[tgt] != 0)
+ {
+ bool match = false;
+
+ if (case_insensitive)
+ {
+ char srcc = char.ToLower(instance[src]);
+ char tgtc = char.ToLower(text[tgt]);
+ match = srcc == tgtc;
+ }
+ else
+ {
+ match = instance[src] == text[tgt];
+ }
+ if (match)
+ {
+ src++;
+ if (instance[src] == 0)
+ return true;
+ }
+
+ tgt++;
+ }
+
+ return false;
+ }
+
+ // <summary>
+ // Check whether this string is a subsequence of the given string, considering case.
+ // </summary>
+ public static bool is_subsequence_of(this string instance, string text)
+ {
+ return instance.is_subsequence_of(text, false);
+ }
+
+ // <summary>
+ // Check whether this string is a subsequence of the given string, without considering case.
+ // </summary>
+ public static bool is_subsequence_ofi(this string instance, string text)
+ {
+ return instance.is_subsequence_of(text, true);
+ }
+
+ // <summary>
+ // Check whether the string contains a valid float.
+ // </summary>
+ public static bool is_valid_float(this string instance)
+ {
+ float f;
+ return float.TryParse(instance, out f);
+ }
+
+ // <summary>
+ // Check whether the string contains a valid color in HTML notation.
+ // </summary>
+ public static bool is_valid_html_color(this string instance)
+ {
+ return Color.html_is_valid(instance);
+ }
+
+ // <summary>
+ // Check whether the string is a valid identifier. As is common in programming languages, a valid identifier may contain only letters, digits and underscores (_) and the first character may not be a digit.
+ // </summary>
+ public static bool is_valid_identifier(this string instance)
+ {
+ int len = instance.Length;
+
+ if (len == 0)
+ return false;
+
+ for (int i = 0; i < len; i++)
+ {
+ if (i == 0)
+ {
+ if (instance[0] >= '0' && instance[0] <= '9')
+ return false; // Don't start with number plz
+ }
+
+ bool valid_char = (instance[i] >= '0' && instance[i] <= '9') || (instance[i] >= 'a' && instance[i] <= 'z') || (instance[i] >= 'A' && instance[i] <= 'Z') || instance[i] == '_';
+
+ if (!valid_char)
+ return false;
+ }
+
+ return true;
+ }
+
+ // <summary>
+ // Check whether the string contains a valid integer.
+ // </summary>
+ public static bool is_valid_integer(this string instance)
+ {
+ int f;
+ return int.TryParse(instance, out f);
+ }
+
+ // <summary>
+ // Check whether the string contains a valid IP address.
+ // </summary>
+ public static bool is_valid_ip_address(this string instance)
+ {
+ string[] ip = instance.split(".");
+
+ if (ip.Length != 4)
+ return false;
+
+ for (int i = 0; i < ip.Length; i++)
+ {
+ string n = ip[i];
+ if (!n.is_valid_integer())
+ return false;
+
+ int val = n.to_int();
+ if (val < 0 || val > 255)
+ return false;
+ }
+
+ return true;
+ }
+
+ // <summary>
+ // Return a copy of the string with special characters escaped using the JSON standard.
+ // </summary>
+ public static string json_escape(this string instance)
+ {
+ StringBuilder sb = new StringBuilder(string.Copy(instance));
+
+ sb.Replace("\\", "\\\\");
+ sb.Replace("\b", "\\b");
+ sb.Replace("\f", "\\f");
+ sb.Replace("\n", "\\n");
+ sb.Replace("\r", "\\r");
+ sb.Replace("\t", "\\t");
+ sb.Replace("\v", "\\v");
+ sb.Replace("\"", "\\\"");
+
+ return sb.ToString();
+ }
+
+ // <summary>
+ // Return an amount of characters from the left of the string.
+ // </summary>
+ public static string left(this string instance, int pos)
+ {
+ if (pos <= 0)
+ return string.Empty;
+
+ if (pos >= instance.Length)
+ return instance;
+
+ return instance.Substring(0, pos);
+ }
+
+ /// <summary>
+ /// Return the length of the string in characters.
+ /// </summary>
+ public static int length(this string instance)
+ {
+ return instance.Length;
+ }
+
+ // <summary>
+ // Do a simple expression match, where '*' matches zero or more arbitrary characters and '?' matches any single character except '.'.
+ // </summary>
+ public static bool expr_match(this string instance, string expr, bool case_sensitive)
+ {
+ if (expr.Length == 0 || instance.Length == 0)
+ return false;
+
+ switch (expr[0])
+ {
+ case '\0':
+ return instance[0] == 0;
+ case '*':
+ return expr_match(expr + 1, instance, case_sensitive) || (instance[0] != 0 && expr_match(expr, instance + 1, case_sensitive));
+ case '?':
+ return instance[0] != 0 && instance[0] != '.' && expr_match(expr + 1, instance + 1, case_sensitive);
+ default:
+ return (case_sensitive ? instance[0] == expr[0] : char.ToUpper(instance[0]) == char.ToUpper(expr[0])) &&
+ expr_match(expr + 1, instance + 1, case_sensitive);
+ }
+ }
+
+ // <summary>
+ // Do a simple case sensitive expression match, using ? and * wildcards (see [method expr_match]).
+ // </summary>
+ public static bool match(this string instance, string expr)
+ {
+ return instance.expr_match(expr, true);
+ }
+
+ // <summary>
+ // Do a simple case insensitive expression match, using ? and * wildcards (see [method expr_match]).
+ // </summary>
+ public static bool matchn(this string instance, string expr)
+ {
+ return instance.expr_match(expr, false);
+ }
+
+ // <summary>
+ // Return the MD5 hash of the string as an array of bytes.
+ // </summary>
+ public static byte[] md5_buffer(this string instance)
+ {
+ return NativeCalls.godot_icall_String_md5_buffer(instance);
+ }
+
+ // <summary>
+ // Return the MD5 hash of the string as a string.
+ // </summary>
+ public static string md5_text(this string instance)
+ {
+ return NativeCalls.godot_icall_String_md5_text(instance);
+ }
+
+ // <summary>
+ // Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
+ // </summary>
+ public static int nocasecmp_to(this string instance, string to)
+ {
+ if (instance.empty())
+ return to.empty() ? 0 : -1;
+
+ if (to.empty())
+ return 1;
+
+ int instance_idx = 0;
+ int to_idx = 0;
+
+ while (true)
+ {
+ if (to[to_idx] == 0 && instance[instance_idx] == 0)
+ return 0; // We're equal
+ else if (instance[instance_idx] == 0)
+ return -1; // If this is empty, and the other one is not, then we're less... I think?
+ else if (to[to_idx] == 0)
+ return 1; // Otherwise the other one is smaller..
+ else if (char.ToUpper(instance[instance_idx]) < char.ToUpper(to[to_idx])) // More than
+ return -1;
+ else if (char.ToUpper(instance[instance_idx]) > char.ToUpper(to[to_idx])) // Less than
+ return 1;
+
+ instance_idx++;
+ to_idx++;
+ }
+ }
+
+ // <summary>
+ // Return the character code at position [code]at[/code].
+ // </summary>
+ public static int ord_at(this string instance, int at)
+ {
+ return instance[at];
+ }
+
+ // <summary>
+ // Format a number to have an exact number of [code]digits[/code] after the decimal point.
+ // </summary>
+ public static string pad_decimals(this string instance, int digits)
+ {
+ int c = instance.find(".");
+
+ if (c == -1)
+ {
+ if (digits <= 0)
+ return instance;
+
+ instance += ".";
+ c = instance.Length - 1;
+ }
+ else
+ {
+ if (digits <= 0)
+ return instance.Substring(0, c);
+ }
+
+ if (instance.Length - (c + 1) > digits)
+ {
+ instance = instance.Substring(0, c + digits + 1);
+ }
+ else
+ {
+ while (instance.Length - (c + 1) < digits)
+ {
+ instance += "0";
+ }
+ }
+
+ return instance;
+ }
+
+ // <summary>
+ // Format a number to have an exact number of [code]digits[/code] before the decimal point.
+ // </summary>
+ public static string pad_zeros(this string instance, int digits)
+ {
+ string s = instance;
+ int end = s.find(".");
+
+ if (end == -1)
+ end = s.Length;
+
+ if (end == 0)
+ return s;
+
+ int begin = 0;
+
+ while (begin < end && (s[begin] < '0' || s[begin] > '9'))
+ {
+ begin++;
+ }
+
+ if (begin >= end)
+ return s;
+
+ while (end - begin < digits)
+ {
+ s = s.Insert(begin, "0");
+ end++;
+ }
+
+ return s;
+ }
+
+ // <summary>
+ // Decode a percent-encoded string. See [method percent_encode].
+ // </summary>
+ public static string percent_decode(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 percent_encode(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 plus_file(this string instance, string file)
+ {
+ if (instance.Length > 0 && instance[instance.Length - 1] == '/')
+ return instance + file;
+ else
+ return instance + "/" + file;
+ }
+
+ // <summary>
+ // Replace occurrences of a substring for different ones inside the string.
+ // </summary>
+ public static string replace(this string instance, string what, string forwhat)
+ {
+ return instance.Replace(what, forwhat);
+ }
+
+ // <summary>
+ // Replace occurrences of a substring for different ones inside the string, but search case-insensitive.
+ // </summary>
+ public static string replacen(this string instance, string what, string forwhat)
+ {
+ return Regex.Replace(instance, what, forwhat, RegexOptions.IgnoreCase);
+ }
+
+ // <summary>
+ // Perform a search for a substring, but start from the end of the string instead of the beginning.
+ // </summary>
+ public static int rfind(this string instance, string what, int from = -1)
+ {
+ return NativeCalls.godot_icall_String_rfind(instance, what, from);
+ }
+
+ // <summary>
+ // Perform a search for a substring, but start from the end of the string instead of the beginning. Also search case-insensitive.
+ // </summary>
+ public static int rfindn(this string instance, string what, int from = -1)
+ {
+ return NativeCalls.godot_icall_String_rfindn(instance, what, from);
+ }
+
+ // <summary>
+ // Return the right side of the string from a given position.
+ // </summary>
+ public static string right(this string instance, int pos)
+ {
+ if (pos >= instance.Length)
+ return instance;
+
+ if (pos < 0)
+ return string.Empty;
+
+ return instance.Substring(pos, (instance.Length - pos));
+ }
+
+ public static byte[] sha256_buffer(this string instance)
+ {
+ return NativeCalls.godot_icall_String_sha256_buffer(instance);
+ }
+
+ // <summary>
+ // Return the SHA-256 hash of the string as a string.
+ // </summary>
+ public static string sha256_text(this string instance)
+ {
+ return NativeCalls.godot_icall_String_sha256_text(instance);
+ }
+
+ // <summary>
+ // Return the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar.
+ // </summary>
+ public static float similarity(this string instance, string text)
+ {
+ if (instance == text)
+ {
+ // Equal strings are totally similar
+ return 1.0f;
+ }
+ if (instance.Length < 2 || text.Length < 2)
+ {
+ // No way to calculate similarity without a single bigram
+ return 0.0f;
+ }
+
+ string[] src_bigrams = instance.bigrams();
+ string[] tgt_bigrams = text.bigrams();
+
+ int src_size = src_bigrams.Length;
+ int tgt_size = tgt_bigrams.Length;
+
+ float sum = src_size + tgt_size;
+ float inter = 0;
+
+ for (int i = 0; i < src_size; i++)
+ {
+ for (int j = 0; j < tgt_size; j++)
+ {
+ if (src_bigrams[i] == tgt_bigrams[j])
+ {
+ inter++;
+ break;
+ }
+ }
+ }
+
+ return (2.0f * inter) / sum;
+ }
+
+ // <summary>
+ // Split the string by a divisor string, return an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",".
+ // </summary>
+ public static string[] split(this string instance, string divisor, bool allow_empty = true)
+ {
+ return instance.Split(new string[] { divisor }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
+ // <summary>
+ // Split the string in floats by using a divisor string, return an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",".
+ // </summary>
+ public static float[] split_floats(this string instance, string divisor, bool allow_empty = true)
+ {
+ List<float> ret = new List<float>();
+ int from = 0;
+ int len = instance.Length;
+
+ while (true)
+ {
+ int end = instance.find(divisor, from);
+ if (end < 0)
+ end = len;
+ if (allow_empty || (end > from))
+ ret.Add(float.Parse(instance.Substring(from)));
+ if (end == len)
+ break;
+
+ from = end + divisor.Length;
+ }
+
+ return ret.ToArray();
+ }
+
+ private static readonly char[] non_printable = {
+ (char)00, (char)01, (char)02, (char)03, (char)04, (char)05,
+ (char)06, (char)07, (char)08, (char)09, (char)10, (char)11,
+ (char)12, (char)13, (char)14, (char)15, (char)16, (char)17,
+ (char)18, (char)19, (char)20, (char)21, (char)22, (char)23,
+ (char)24, (char)25, (char)26, (char)27, (char)28, (char)29,
+ (char)30, (char)31, (char)32
+ };
+
+ // <summary>
+ // Return a copy of the string stripped of any non-printable character at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively.
+ // </summary>
+ public static string strip_edges(this string instance, bool left = true, bool right = true)
+ {
+ if (left)
+ {
+ if (right)
+ return instance.Trim(non_printable);
+ else
+ return instance.TrimStart(non_printable);
+ }
+ else
+ {
+ return instance.TrimEnd(non_printable);
+ }
+ }
+
+ // <summary>
+ // Return part of the string from the position [code]from[/code], with length [code]len[/code].
+ // </summary>
+ public static string substr(this string instance, int from, int len)
+ {
+ return instance.Substring(from, len);
+ }
+
+ // <summary>
+ // Convert the String (which is a character array) to PoolByteArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters.
+ // </summary>
+ public static byte[] to_ascii(this string instance)
+ {
+ return Encoding.ASCII.GetBytes(instance);
+ }
+
+ // <summary>
+ // Convert a string, containing a decimal number, into a [code]float[/code].
+ // </summary>
+ public static float to_float(this string instance)
+ {
+ return float.Parse(instance);
+ }
+
+ // <summary>
+ // Convert a string, containing an integer number, into an [code]int[/code].
+ // </summary>
+ public static int to_int(this string instance)
+ {
+ return int.Parse(instance);
+ }
+
+ // <summary>
+ // Return the string converted to lowercase.
+ // </summary>
+ public static string to_lower(this string instance)
+ {
+ return instance.ToLower();
+ }
+
+ // <summary>
+ // Return the string converted to uppercase.
+ // </summary>
+ public static string to_upper(this string instance)
+ {
+ return instance.ToUpper();
+ }
+
+ // <summary>
+ // Convert the String (which is an array of characters) to PoolByteArray (which is an array of bytes). The conversion is a bit slower than to_ascii(), but supports all UTF-8 characters. Therefore, you should prefer this function over to_ascii().
+ // </summary>
+ public static byte[] to_utf8(this string instance)
+ {
+ return Encoding.UTF8.GetBytes(instance);
+ }
+
+ // <summary>
+ // Return a copy of the string with special characters escaped using the XML standard.
+ // </summary>
+ public static string xml_escape(this string instance)
+ {
+ return SecurityElement.Escape(instance);
+ }
+
+ // <summary>
+ // Return a copy of the string with escaped characters replaced by their meanings according to the XML standard.
+ // </summary>
+ public static string xml_unescape(this string instance)
+ {
+ return SecurityElement.FromString(instance).Text;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/ToolAttribute.cs b/modules/mono/glue/cs_files/ToolAttribute.cs
new file mode 100644
index 0000000000..d8601b5b32
--- /dev/null
+++ b/modules/mono/glue/cs_files/ToolAttribute.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class ToolAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/cs_files/Transform.cs b/modules/mono/glue/cs_files/Transform.cs
new file mode 100644
index 0000000000..74271e758b
--- /dev/null
+++ b/modules/mono/glue/cs_files/Transform.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Transform : IEquatable<Transform>
+ {
+ public Basis basis;
+ public Vector3 origin;
+
+ public Transform affine_inverse()
+ {
+ Basis basisInv = basis.inverse();
+ return new Transform(basisInv, basisInv.xform(-origin));
+ }
+
+ public Transform inverse()
+ {
+ Basis basisTr = basis.transposed();
+ return new Transform(basisTr, basisTr.xform(-origin));
+ }
+
+ public Transform looking_at(Vector3 target, Vector3 up)
+ {
+ Transform t = this;
+ t.set_look_at(origin, target, up);
+ return t;
+ }
+
+ public Transform orthonormalized()
+ {
+ return new Transform(basis.orthonormalized(), origin);
+ }
+
+ public Transform rotated(Vector3 axis, float phi)
+ {
+ return new Transform(new Basis(axis, phi), new Vector3()) * this;
+ }
+
+ public Transform scaled(Vector3 scale)
+ {
+ return new Transform(basis.scaled(scale), origin * scale);
+ }
+
+ public void set_look_at(Vector3 eye, Vector3 target, Vector3 up)
+ {
+ // Make rotation matrix
+ // Z vector
+ Vector3 zAxis = eye - target;
+
+ zAxis.normalize();
+
+ Vector3 yAxis = up;
+
+ Vector3 xAxis = yAxis.cross(zAxis);
+
+ // Recompute Y = Z cross X
+ yAxis = zAxis.cross(xAxis);
+
+ xAxis.normalize();
+ yAxis.normalize();
+
+ basis = Basis.create_from_axes(xAxis, yAxis, zAxis);
+
+ origin = eye;
+ }
+
+ public Transform translated(Vector3 ofs)
+ {
+ return new Transform(basis, new Vector3
+ (
+ origin[0] += basis[0].dot(ofs),
+ origin[1] += basis[1].dot(ofs),
+ origin[2] += basis[2].dot(ofs)
+ ));
+ }
+
+ public Vector3 xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ basis[0].dot(v) + origin.x,
+ basis[1].dot(v) + origin.y,
+ basis[2].dot(v) + origin.z
+ );
+ }
+
+ public Vector3 xform_inv(Vector3 v)
+ {
+ Vector3 vInv = v - origin;
+
+ return new Vector3
+ (
+ (basis[0, 0] * vInv.x) + (basis[1, 0] * vInv.y) + (basis[2, 0] * vInv.z),
+ (basis[0, 1] * vInv.x) + (basis[1, 1] * vInv.y) + (basis[2, 1] * vInv.z),
+ (basis[0, 2] * vInv.x) + (basis[1, 2] * vInv.y) + (basis[2, 2] * vInv.z)
+ );
+ }
+
+ public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin)
+ {
+ this.basis = Basis.create_from_axes(xAxis, yAxis, zAxis);
+ this.origin = origin;
+ }
+
+ public Transform(Quat quat, Vector3 origin)
+ {
+ this.basis = new Basis(quat);
+ this.origin = origin;
+ }
+
+ public Transform(Basis basis, Vector3 origin)
+ {
+ this.basis = basis;
+ this.origin = origin;
+ }
+
+ public static Transform operator *(Transform left, Transform right)
+ {
+ left.origin = left.xform(right.origin);
+ left.basis *= right.basis;
+ return left;
+ }
+
+ public static bool operator ==(Transform left, Transform right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Transform left, Transform right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Transform)
+ {
+ return Equals((Transform)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Transform other)
+ {
+ return basis.Equals(other.basis) && origin.Equals(other.origin);
+ }
+
+ public override int GetHashCode()
+ {
+ return basis.GetHashCode() ^ origin.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.basis.ToString(),
+ this.origin.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.basis.ToString(format),
+ this.origin.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Transform2D.cs b/modules/mono/glue/cs_files/Transform2D.cs
new file mode 100644
index 0000000000..526dc767c6
--- /dev/null
+++ b/modules/mono/glue/cs_files/Transform2D.cs
@@ -0,0 +1,356 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Transform2D : IEquatable<Transform2D>
+ {
+ private static readonly Transform2D identity = new Transform2D
+ (
+ new Vector2(1f, 0f),
+ new Vector2(0f, 1f),
+ new Vector2(0f, 0f)
+ );
+
+ public Vector2 x;
+ public Vector2 y;
+ public Vector2 o;
+
+ public static Transform2D Identity
+ {
+ get { return identity; }
+ }
+
+ public Vector2 Origin
+ {
+ get { return o; }
+ }
+
+ public float Rotation
+ {
+ get { return Mathf.atan2(y.x, o.y); }
+ }
+
+ public Vector2 Scale
+ {
+ get { return new Vector2(x.length(), y.length()); }
+ }
+
+ public Vector2 this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return o;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ o = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+
+ public float this[int index, int axis]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x[axis];
+ case 1:
+ return y[axis];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x[axis] = value;
+ return;
+ case 1:
+ y[axis] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Transform2D affine_inverse()
+ {
+ Transform2D inv = this;
+
+ float det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1];
+
+ if (det == 0)
+ {
+ return new Transform2D
+ (
+ float.NaN, float.NaN,
+ float.NaN, float.NaN,
+ float.NaN, float.NaN
+ );
+ }
+
+ float idet = 1.0f / det;
+
+ float temp = this[0, 0];
+ this[0, 0] = this[1, 1];
+ this[1, 1] = temp;
+
+ this[0] *= new Vector2(idet, -idet);
+ this[1] *= new Vector2(-idet, idet);
+
+ this[2] = basis_xform(-this[2]);
+
+ return inv;
+ }
+
+ public Vector2 basis_xform(Vector2 v)
+ {
+ return new Vector2(tdotx(v), tdoty(v));
+ }
+
+ public Vector2 basis_xform_inv(Vector2 v)
+ {
+ return new Vector2(x.dot(v), y.dot(v));
+ }
+
+ public Transform2D interpolate_with(Transform2D m, float c)
+ {
+ float r1 = Rotation;
+ float r2 = m.Rotation;
+
+ Vector2 s1 = Scale;
+ Vector2 s2 = m.Scale;
+
+ // Slerp rotation
+ Vector2 v1 = new Vector2(Mathf.cos(r1), Mathf.sin(r1));
+ Vector2 v2 = new Vector2(Mathf.cos(r2), Mathf.sin(r2));
+
+ float dot = v1.dot(v2);
+
+ // Clamp dot to [-1, 1]
+ dot = (dot < -1.0f) ? -1.0f : ((dot > 1.0f) ? 1.0f : dot);
+
+ Vector2 v = new Vector2();
+
+ if (dot > 0.9995f)
+ {
+ // Linearly interpolate to avoid numerical precision issues
+ v = v1.linear_interpolate(v2, c).normalized();
+ }
+ else
+ {
+ float angle = c * Mathf.acos(dot);
+ Vector2 v3 = (v2 - v1 * dot).normalized();
+ v = v1 * Mathf.cos(angle) + v3 * Mathf.sin(angle);
+ }
+
+ // Extract parameters
+ Vector2 p1 = Origin;
+ Vector2 p2 = m.Origin;
+
+ // Construct matrix
+ Transform2D res = new Transform2D(Mathf.atan2(v.y, v.x), p1.linear_interpolate(p2, c));
+ Vector2 scale = s1.linear_interpolate(s2, c);
+ res.x *= scale;
+ res.y *= scale;
+
+ return res;
+ }
+
+ public Transform2D inverse()
+ {
+ Transform2D inv = this;
+
+ // Swap
+ float temp = inv.x.y;
+ inv.x.y = inv.y.x;
+ inv.y.x = temp;
+
+ inv.o = inv.basis_xform(-inv.o);
+
+ return inv;
+ }
+
+ public Transform2D orthonormalized()
+ {
+ Transform2D on = this;
+
+ Vector2 onX = on.x;
+ Vector2 onY = on.y;
+
+ onX.normalize();
+ onY = onY - onX * (onX.dot(onY));
+ onY.normalize();
+
+ on.x = onX;
+ on.y = onY;
+
+ return on;
+ }
+
+ public Transform2D rotated(float phi)
+ {
+ return this * new Transform2D(phi, new Vector2());
+ }
+
+ public Transform2D scaled(Vector2 scale)
+ {
+ Transform2D copy = this;
+ copy.x *= scale;
+ copy.y *= scale;
+ copy.o *= scale;
+ return copy;
+ }
+
+ private float tdotx(Vector2 with)
+ {
+ return this[0, 0] * with[0] + this[1, 0] * with[1];
+ }
+
+ private float tdoty(Vector2 with)
+ {
+ return this[0, 1] * with[0] + this[1, 1] * with[1];
+ }
+
+ public Transform2D translated(Vector2 offset)
+ {
+ Transform2D copy = this;
+ copy.o += copy.basis_xform(offset);
+ return copy;
+ }
+
+ public Vector2 xform(Vector2 v)
+ {
+ return new Vector2(tdotx(v), tdoty(v)) + o;
+ }
+
+ public Vector2 xform_inv(Vector2 v)
+ {
+ Vector2 vInv = v - o;
+ return new Vector2(x.dot(vInv), y.dot(vInv));
+ }
+
+ public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin)
+ {
+ this.x = xAxis;
+ this.y = yAxis;
+ this.o = origin;
+ }
+ public Transform2D(float xx, float xy, float yx, float yy, float ox, float oy)
+ {
+ this.x = new Vector2(xx, xy);
+ this.y = new Vector2(yx, yy);
+ this.o = new Vector2(ox, oy);
+ }
+
+ public Transform2D(float rot, Vector2 pos)
+ {
+ float cr = Mathf.cos(rot);
+ float sr = Mathf.sin(rot);
+ x.x = cr;
+ y.y = cr;
+ x.y = -sr;
+ y.x = sr;
+ o = pos;
+ }
+
+ public static Transform2D operator *(Transform2D left, Transform2D right)
+ {
+ left.o = left.xform(right.o);
+
+ float x0, x1, y0, y1;
+
+ x0 = left.tdotx(right.x);
+ x1 = left.tdoty(right.x);
+ y0 = left.tdotx(right.y);
+ y1 = left.tdoty(right.y);
+
+ left.x.x = x0;
+ left.x.y = x1;
+ left.y.x = y0;
+ left.y.y = y1;
+
+ return left;
+ }
+
+ public static bool operator ==(Transform2D left, Transform2D right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Transform2D left, Transform2D right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Transform2D)
+ {
+ return Equals((Transform2D)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Transform2D other)
+ {
+ return x.Equals(other.x) && y.Equals(other.y) && o.Equals(other.o);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ y.GetHashCode() ^ o.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.o.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.o.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Vector2.cs b/modules/mono/glue/cs_files/Vector2.cs
new file mode 100644
index 0000000000..28fedc365b
--- /dev/null
+++ b/modules/mono/glue/cs_files/Vector2.cs
@@ -0,0 +1,362 @@
+using System;
+using System.Runtime.InteropServices;
+
+// file: core/math/math_2d.h
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/math/math_2d.cpp
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector2 : IEquatable<Vector2>
+ {
+ public float x;
+ public float y;
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal void normalize()
+ {
+ float length = x * x + y * y;
+
+ if (length != 0f)
+ {
+ length = Mathf.sqrt(length);
+ x /= length;
+ y /= length;
+ }
+ }
+
+ private float cross(Vector2 b)
+ {
+ return x * b.y - y * b.x;
+ }
+
+ public Vector2 abs()
+ {
+ return new Vector2(Mathf.abs(x), Mathf.abs(y));
+ }
+
+ public float angle()
+ {
+ return Mathf.atan2(y, x);
+ }
+
+ public float angle_to(Vector2 to)
+ {
+ return Mathf.atan2(cross(to), dot(to));
+ }
+
+ public float angle_to_point(Vector2 to)
+ {
+ return Mathf.atan2(x - to.x, y - to.y);
+ }
+
+ public float aspect()
+ {
+ return x / y;
+ }
+
+ public Vector2 bounce(Vector2 n)
+ {
+ return -reflect(n);
+ }
+
+ public Vector2 clamped(float length)
+ {
+ Vector2 v = this;
+ float l = this.length();
+
+ if (l > 0 && length < l)
+ {
+ v /= l;
+ v *= length;
+ }
+
+ return v;
+ }
+
+ public Vector2 cubic_interpolate(Vector2 b, Vector2 preA, Vector2 postB, float t)
+ {
+ Vector2 p0 = preA;
+ Vector2 p1 = this;
+ Vector2 p2 = b;
+ Vector2 p3 = postB;
+
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ return 0.5f * ((p1 * 2.0f) +
+ (-p0 + p2) * t +
+ (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 +
+ (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
+ }
+
+ public float distance_squared_to(Vector2 to)
+ {
+ return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
+ }
+
+ public float distance_to(Vector2 to)
+ {
+ return Mathf.sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y));
+ }
+
+ public float dot(Vector2 with)
+ {
+ return x * with.x + y * with.y;
+ }
+
+ public Vector2 floor()
+ {
+ return new Vector2(Mathf.floor(x), Mathf.floor(y));
+ }
+
+ public bool is_normalized()
+ {
+ return Mathf.abs(length_squared() - 1.0f) < Mathf.Epsilon;
+ }
+
+ public float length()
+ {
+ return Mathf.sqrt(x * x + y * y);
+ }
+
+ public float length_squared()
+ {
+ return x * x + y * y;
+ }
+
+ public Vector2 linear_interpolate(Vector2 b, float t)
+ {
+ Vector2 res = this;
+
+ res.x += (t * (b.x - x));
+ res.y += (t * (b.y - y));
+
+ return res;
+ }
+
+ public Vector2 normalized()
+ {
+ Vector2 result = this;
+ result.normalize();
+ return result;
+ }
+
+ public Vector2 reflect(Vector2 n)
+ {
+ return 2.0f * n * dot(n) - this;
+ }
+
+ public Vector2 rotated(float phi)
+ {
+ float rads = angle() + phi;
+ return new Vector2(Mathf.cos(rads), Mathf.sin(rads)) * length();
+ }
+
+ public Vector2 slide(Vector2 n)
+ {
+ return this - n * dot(n);
+ }
+
+ public Vector2 snapped(Vector2 by)
+ {
+ return new Vector2(Mathf.stepify(x, by.x), Mathf.stepify(y, by.y));
+ }
+
+ public Vector2 tangent()
+ {
+ return new Vector2(y, -x);
+ }
+
+ public Vector2(float x, float y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ public static Vector2 operator +(Vector2 left, Vector2 right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ return left;
+ }
+
+ public static Vector2 operator -(Vector2 left, Vector2 right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ return left;
+ }
+
+ public static Vector2 operator -(Vector2 vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ return vec;
+ }
+
+ public static Vector2 operator *(Vector2 vec, float scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ return vec;
+ }
+
+ public static Vector2 operator *(float scale, Vector2 vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ return vec;
+ }
+
+ public static Vector2 operator *(Vector2 left, Vector2 right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ return left;
+ }
+
+ public static Vector2 operator /(Vector2 vec, float scale)
+ {
+ vec.x /= scale;
+ vec.y /= scale;
+ return vec;
+ }
+
+ public static Vector2 operator /(Vector2 left, Vector2 right)
+ {
+ left.x /= right.x;
+ left.y /= right.y;
+ return left;
+ }
+
+ public static bool operator ==(Vector2 left, Vector2 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector2 left, Vector2 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y < right.y;
+ }
+ else
+ {
+ return left.x < right.x;
+ }
+ }
+
+ public static bool operator >(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y > right.y;
+ }
+ else
+ {
+ return left.x > right.x;
+ }
+ }
+
+ public static bool operator <=(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y <= right.y;
+ }
+ else
+ {
+ return left.x <= right.x;
+ }
+ }
+
+ public static bool operator >=(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y >= right.y;
+ }
+ else
+ {
+ return left.x >= right.x;
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector2)
+ {
+ return Equals((Vector2)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Vector2 other)
+ {
+ return x == other.x && y == other.y;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Vector3.cs b/modules/mono/glue/cs_files/Vector3.cs
new file mode 100644
index 0000000000..c023cd83cf
--- /dev/null
+++ b/modules/mono/glue/cs_files/Vector3.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Runtime.InteropServices;
+
+// file: core/math/vector3.h
+// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
+// file: core/math/vector3.cpp
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector3 : IEquatable<Vector3>
+ {
+ public enum Axis
+ {
+ X = 0,
+ Y,
+ Z
+ }
+
+ public float x;
+ public float y;
+ public float z;
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal void normalize()
+ {
+ float length = this.length();
+
+ if (length == 0f)
+ {
+ x = y = z = 0f;
+ }
+ else
+ {
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+ }
+
+ public Vector3 abs()
+ {
+ return new Vector3(Mathf.abs(x), Mathf.abs(y), Mathf.abs(z));
+ }
+
+ public float angle_to(Vector3 to)
+ {
+ return Mathf.atan2(cross(to).length(), dot(to));
+ }
+
+ public Vector3 bounce(Vector3 n)
+ {
+ return -reflect(n);
+ }
+
+ public Vector3 ceil()
+ {
+ return new Vector3(Mathf.ceil(x), Mathf.ceil(y), Mathf.ceil(z));
+ }
+
+ public Vector3 cross(Vector3 b)
+ {
+ return new Vector3
+ (
+ (y * b.z) - (z * b.y),
+ (z * b.x) - (x * b.z),
+ (x * b.y) - (y * b.x)
+ );
+ }
+
+ public Vector3 cubic_interpolate(Vector3 b, Vector3 preA, Vector3 postB, float t)
+ {
+ Vector3 p0 = preA;
+ Vector3 p1 = this;
+ Vector3 p2 = b;
+ Vector3 p3 = postB;
+
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ return 0.5f * (
+ (p1 * 2.0f) + (-p0 + p2) * t +
+ (2.0f * p0 - 5.0f * p1 + 4f * p2 - p3) * t2 +
+ (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3
+ );
+ }
+
+ public float distance_squared_to(Vector3 b)
+ {
+ return (b - this).length_squared();
+ }
+
+ public float distance_to(Vector3 b)
+ {
+ return (b - this).length();
+ }
+
+ public float dot(Vector3 b)
+ {
+ return x * b.x + y * b.y + z * b.z;
+ }
+
+ public Vector3 floor()
+ {
+ return new Vector3(Mathf.floor(x), Mathf.floor(y), Mathf.floor(z));
+ }
+
+ public Vector3 inverse()
+ {
+ return new Vector3(1.0f / x, 1.0f / y, 1.0f / z);
+ }
+
+ public bool is_normalized()
+ {
+ return Mathf.abs(length_squared() - 1.0f) < Mathf.Epsilon;
+ }
+
+ public float length()
+ {
+ float x2 = x * x;
+ float y2 = y * y;
+ float z2 = z * z;
+
+ return Mathf.sqrt(x2 + y2 + z2);
+ }
+
+ public float length_squared()
+ {
+ float x2 = x * x;
+ float y2 = y * y;
+ float z2 = z * z;
+
+ return x2 + y2 + z2;
+ }
+
+ public Vector3 linear_interpolate(Vector3 b, float t)
+ {
+ return new Vector3
+ (
+ x + (t * (b.x - x)),
+ y + (t * (b.y - y)),
+ z + (t * (b.z - z))
+ );
+ }
+
+ public Axis max_axis()
+ {
+ return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
+ }
+
+ public Axis min_axis()
+ {
+ return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
+ }
+
+ public Vector3 normalized()
+ {
+ Vector3 v = this;
+ v.normalize();
+ return v;
+ }
+
+ public Basis outer(Vector3 b)
+ {
+ return new Basis(
+ new Vector3(x * b.x, x * b.y, x * b.z),
+ new Vector3(y * b.x, y * b.y, y * b.z),
+ new Vector3(z * b.x, z * b.y, z * b.z)
+ );
+ }
+
+ public Vector3 reflect(Vector3 n)
+ {
+#if DEBUG
+ if (!n.is_normalized())
+ throw new ArgumentException(String.Format("{0} is not normalized", n), nameof(n));
+#endif
+ return 2.0f * n * dot(n) - this;
+ }
+
+ public Vector3 rotated(Vector3 axis, float phi)
+ {
+ return new Basis(axis, phi).xform(this);
+ }
+
+ public Vector3 slide(Vector3 n)
+ {
+ return this - n * dot(n);
+ }
+
+ public Vector3 snapped(Vector3 by)
+ {
+ return new Vector3
+ (
+ Mathf.stepify(x, by.x),
+ Mathf.stepify(y, by.y),
+ Mathf.stepify(z, by.z)
+ );
+ }
+
+ public Basis to_diagonal_matrix()
+ {
+ return new Basis(
+ x, 0f, 0f,
+ 0f, y, 0f,
+ 0f, 0f, z
+ );
+ }
+
+ public Vector3(float x, float y, float z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public static Vector3 operator +(Vector3 left, Vector3 right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ left.z += right.z;
+ return left;
+ }
+
+ public static Vector3 operator -(Vector3 left, Vector3 right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ left.z -= right.z;
+ return left;
+ }
+
+ public static Vector3 operator -(Vector3 vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ vec.z = -vec.z;
+ return vec;
+ }
+
+ public static Vector3 operator *(Vector3 vec, float scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ return vec;
+ }
+
+ public static Vector3 operator *(float scale, Vector3 vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ return vec;
+ }
+
+ public static Vector3 operator *(Vector3 left, Vector3 right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ left.z *= right.z;
+ return left;
+ }
+
+ public static Vector3 operator /(Vector3 vec, float scale)
+ {
+ vec.x /= scale;
+ vec.y /= scale;
+ vec.z /= scale;
+ return vec;
+ }
+
+ public static Vector3 operator /(Vector3 left, Vector3 right)
+ {
+ left.x /= right.x;
+ left.y /= right.y;
+ left.z /= right.z;
+ return left;
+ }
+
+ public static bool operator ==(Vector3 left, Vector3 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector3 left, Vector3 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z < right.z;
+ else
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z > right.z;
+ else
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z <= right.z;
+ else
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >=(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z >= right.z;
+ else
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector3)
+ {
+ return Equals((Vector3)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Vector3 other)
+ {
+ return x == other.x && y == other.y && z == other.z;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.z.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.z.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
new file mode 100644
index 0000000000..0751a0160f
--- /dev/null
+++ b/modules/mono/glue/glue_header.h
@@ -0,0 +1,302 @@
+/*************************************************************************/
+/* glue_header.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "../csharp_script.h"
+#include "../mono_gd/gd_mono_class.h"
+#include "../mono_gd/gd_mono_internals.h"
+#include "../mono_gd/gd_mono_marshal.h"
+#include "../signal_awaiter_utils.h"
+
+#include "bind/core_bind.h"
+#include "class_db.h"
+#include "io/marshalls.h"
+#include "object.h"
+#include "os/os.h"
+#include "project_settings.h"
+#include "reference.h"
+#include "variant_parser.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#endif
+
+#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \
+ static ClassDB::ClassInfo *ci = NULL; \
+ if (!ci) { \
+ ci = ClassDB::classes.getptr(m_type); \
+ } \
+ Object *m_instance = ci->creation_func();
+
+void godot_icall_Object_Dtor(Object *ptr) {
+ ERR_FAIL_NULL(ptr);
+ _GodotSharp::get_singleton()->queue_dispose(ptr);
+}
+
+// -- ClassDB --
+
+MethodBind *godot_icall_ClassDB_get_method(MonoString *p_type, MonoString *p_method) {
+ StringName type(GDMonoMarshal::mono_string_to_godot(p_type));
+ StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
+ return ClassDB::get_method(type, method);
+}
+
+// -- SignalAwaiter --
+
+Error godot_icall_Object_connect_signal_awaiter(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) {
+ String signal = GDMonoMarshal::mono_string_to_godot(p_signal);
+ return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
+}
+
+// -- NodePath --
+
+NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) {
+ return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path)));
+}
+
+void godot_icall_NodePath_Dtor(NodePath *p_ptr) {
+ ERR_FAIL_NULL(p_ptr);
+ _GodotSharp::get_singleton()->queue_dispose(p_ptr);
+}
+
+MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
+ return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
+}
+
+MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) {
+ Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer();
+ // TODO Check possible Array/Vector<uint8_t> problem?
+ return GDMonoMarshal::Array_to_mono_array(Variant(ret));
+}
+
+// -- RID --
+
+RID *godot_icall_RID_Ctor(Object *p_from) {
+ Resource *res_from = Object::cast_to<Resource>(p_from);
+
+ if (res_from)
+ return memnew(RID(res_from->get_rid()));
+
+ return memnew(RID);
+}
+
+void godot_icall_RID_Dtor(RID *p_ptr) {
+ ERR_FAIL_NULL(p_ptr);
+ _GodotSharp::get_singleton()->queue_dispose(p_ptr);
+}
+
+// -- String --
+
+MonoString *godot_icall_String_md5_text(MonoString *p_str) {
+ String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text();
+ return GDMonoMarshal::mono_string_from_godot(ret);
+}
+
+int godot_icall_String_rfind(MonoString *p_str, MonoString *p_what, int p_from) {
+ String what = GDMonoMarshal::mono_string_to_godot(p_what);
+ return GDMonoMarshal::mono_string_to_godot(p_str).rfind(what, p_from);
+}
+
+int godot_icall_String_rfindn(MonoString *p_str, MonoString *p_what, int p_from) {
+ String what = GDMonoMarshal::mono_string_to_godot(p_what);
+ return GDMonoMarshal::mono_string_to_godot(p_str).rfindn(what, p_from);
+}
+
+MonoArray *godot_icall_String_sha256_buffer(MonoString *p_str) {
+ Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_buffer();
+ return GDMonoMarshal::Array_to_mono_array(Variant(ret));
+}
+
+MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
+ String ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_text();
+ return GDMonoMarshal::mono_string_from_godot(ret);
+}
+
+// -- Global Scope --
+
+MonoObject *godot_icall_Godot_bytes2var(MonoArray *p_bytes) {
+ Variant ret;
+ PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes);
+ PoolByteArray::Read r = varr.read();
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ if (err != OK) {
+ ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
+ }
+ return GDMonoMarshal::variant_to_mono_object(ret);
+}
+
+MonoObject *godot_icall_Godot_convert(MonoObject *p_what, int p_type) {
+ Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
+ const Variant *args[1] = { &what };
+ Variant::CallError ce;
+ Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce);
+ ERR_FAIL_COND_V(ce.error != Variant::CallError::CALL_OK, NULL);
+ return GDMonoMarshal::variant_to_mono_object(ret);
+}
+
+int godot_icall_Godot_hash(MonoObject *p_var) {
+ return GDMonoMarshal::mono_object_to_variant(p_var).hash();
+}
+
+MonoObject *godot_icall_Godot_instance_from_id(int p_instance_id) {
+ return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(p_instance_id));
+}
+
+void godot_icall_Godot_print(MonoArray *p_what) {
+ Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+ String str;
+ for (int i = 0; i < what.size(); i++)
+ str += what[i].operator String();
+ print_line(str);
+}
+
+void godot_icall_Godot_printerr(MonoArray *p_what) {
+ Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+ String str;
+ for (int i = 0; i < what.size(); i++)
+ str += what[i].operator String();
+ OS::get_singleton()->printerr("%s\n", str.utf8().get_data());
+}
+
+void godot_icall_Godot_printraw(MonoArray *p_what) {
+ Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+ String str;
+ for (int i = 0; i < what.size(); i++)
+ str += what[i].operator String();
+ OS::get_singleton()->print("%s", str.utf8().get_data());
+}
+
+void godot_icall_Godot_prints(MonoArray *p_what) {
+ Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+ String str;
+ for (int i = 0; i < what.size(); i++) {
+ if (i)
+ str += " ";
+ str += what[i].operator String();
+ }
+ print_line(str);
+}
+
+void godot_icall_Godot_printt(MonoArray *p_what) {
+ Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+ String str;
+ for (int i = 0; i < what.size(); i++) {
+ if (i)
+ str += "\t";
+ str += what[i].operator String();
+ }
+ print_line(str);
+}
+
+void godot_icall_Godot_seed(int p_seed) {
+ Math::seed(p_seed);
+}
+
+MonoString *godot_icall_Godot_str(MonoArray *p_what) {
+ String str;
+ Array what = GDMonoMarshal::mono_array_to_Array(p_what);
+
+ for (int i = 0; i < what.size(); i++) {
+ String os = what[i].operator String();
+
+ if (i == 0)
+ str = os;
+ else
+ str += os;
+ }
+
+ return GDMonoMarshal::mono_string_from_godot(str);
+}
+
+MonoObject *godot_icall_Godot_str2var(MonoString *p_str) {
+ Variant ret;
+
+ VariantParser::StreamString ss;
+ ss.s = GDMonoMarshal::mono_string_to_godot(p_str);
+
+ String errs;
+ int line;
+ Error err = VariantParser::parse(&ss, ret, errs, line);
+ if (err != OK) {
+ String err_str = "Parse error at line " + itos(line) + ": " + errs;
+ ERR_PRINTS(err_str);
+ ret = err_str;
+ }
+
+ return GDMonoMarshal::variant_to_mono_object(ret);
+}
+
+bool godot_icall_Godot_type_exists(MonoString *p_type) {
+ return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
+}
+
+MonoArray *godot_icall_Godot_var2bytes(MonoObject *p_var) {
+ Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
+
+ PoolByteArray barr;
+ int len;
+ Error err = encode_variant(var, NULL, len);
+ ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
+ ERR_FAIL_COND_V(err != OK, NULL);
+
+ barr.resize(len);
+ {
+ PoolByteArray::Write w = barr.write();
+ encode_variant(var, w.ptr(), len);
+ }
+
+ return GDMonoMarshal::PoolByteArray_to_mono_array(barr);
+}
+
+MonoString *godot_icall_Godot_var2str(MonoObject *p_var) {
+ String vars;
+ VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars);
+ return GDMonoMarshal::mono_string_from_godot(vars);
+}
+
+MonoObject *godot_icall_Godot_weakref(Object *p_obj) {
+ if (!p_obj)
+ return NULL;
+
+ Ref<WeakRef> wref;
+ Reference *ref = Object::cast_to<Reference>(p_obj);
+
+ if (ref) {
+ REF r = ref;
+ if (!r.is_valid())
+ return NULL;
+
+ wref.instance();
+ wref->set_ref(r);
+ } else {
+ wref.instance();
+ wref->set_obj(p_obj);
+ }
+
+ return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr()));
+}
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
new file mode 100644
index 0000000000..f941a4d6c5
--- /dev/null
+++ b/modules/mono/godotsharp_defs.h
@@ -0,0 +1,41 @@
+/*************************************************************************/
+/* godotsharp_defs.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GODOTSHARP_DEFS_H
+#define GODOTSHARP_DEFS_H
+
+#define BINDINGS_NAMESPACE "Godot"
+#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
+#define BINDINGS_PTR_FIELD "ptr"
+#define BINDINGS_NATIVE_NAME_FIELD "nativeName"
+#define API_ASSEMBLY_NAME "GodotSharp"
+#define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
+#define EDITOR_TOOLS_ASSEMBLY_NAME "GodotSharpTools"
+
+#endif // GODOTSHARP_DEFS_H
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
new file mode 100644
index 0000000000..7cc2168b70
--- /dev/null
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* godotsharp_dirs.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "godotsharp_dirs.h"
+
+#include "os/os.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#include "os/dir_access.h"
+#include "project_settings.h"
+#include "version.h"
+#endif
+
+namespace GodotSharpDirs {
+
+String _get_expected_build_config() {
+#ifdef TOOLS_ENABLED
+ return "Tools";
+#else
+
+#ifdef DEBUG_ENABLED
+ return "Debug";
+#else
+ return "Release";
+#endif
+
+#endif
+}
+
+String _get_mono_user_dir() {
+#ifdef TOOLS_ENABLED
+ if (EditorSettings::get_singleton()) {
+ return EditorSettings::get_singleton()->get_settings_path().plus_file("mono");
+ } else {
+ String settings_path;
+
+ String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
+ DirAccessRef d = DirAccess::create_for_path(exe_dir);
+
+ if (d->file_exists("._sc_") || d->file_exists("_sc_")) {
+ // contain yourself
+ settings_path = exe_dir.plus_file("editor_data");
+ } else {
+ if (OS::get_singleton()->has_environment("APPDATA")) {
+ String app_data = OS::get_singleton()->get_environment("APPDATA").replace("\\", "/");
+ settings_path = app_data.plus_file(String(_MKSTR(VERSION_SHORT_NAME)).capitalize());
+ } else if (OS::get_singleton()->has_environment("HOME")) {
+ String home = OS::get_singleton()->get_environment("HOME");
+ settings_path = home.plus_file("." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower());
+ }
+ }
+
+ return settings_path.plus_file("mono");
+ }
+#else
+ return OS::get_singleton()->get_data_dir().plus_file("mono");
+#endif
+}
+
+class _GodotSharpDirs {
+
+public:
+ String res_data_dir;
+ String res_metadata_dir;
+ String res_assemblies_dir;
+ String res_config_dir;
+ String res_temp_dir;
+ String res_temp_assemblies_base_dir;
+ String res_temp_assemblies_dir;
+ String mono_user_dir;
+ String mono_logs_dir;
+
+#ifdef TOOLS_ENABLED
+ String mono_solutions_dir;
+ String build_logs_dir;
+ String sln_filepath;
+ String csproj_filepath;
+#endif
+
+private:
+ _GodotSharpDirs() {
+ res_data_dir = "res://.mono";
+ res_metadata_dir = res_data_dir.plus_file("metadata");
+ res_assemblies_dir = res_data_dir.plus_file("assemblies");
+ res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
+
+ // TODO use paths from csproj
+ res_temp_dir = res_data_dir.plus_file("temp");
+ res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin");
+ res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config());
+
+ mono_user_dir = _get_mono_user_dir();
+ mono_logs_dir = mono_user_dir.plus_file("mono_logs");
+
+#ifdef TOOLS_ENABLED
+ mono_solutions_dir = mono_user_dir.plus_file("solutions");
+ build_logs_dir = mono_user_dir.plus_file("build_logs");
+
+ String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
+
+ String base_path = String("res://") + name;
+
+ sln_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".sln");
+ csproj_filepath = ProjectSettings::get_singleton()->globalize_path(base_path + ".csproj");
+#endif
+ }
+
+ _GodotSharpDirs(const _GodotSharpDirs &);
+ _GodotSharpDirs &operator=(const _GodotSharpDirs &);
+
+public:
+ static _GodotSharpDirs &get_singleton() {
+ static _GodotSharpDirs singleton;
+ return singleton;
+ }
+};
+
+String get_res_data_dir() {
+ return _GodotSharpDirs::get_singleton().res_data_dir;
+}
+
+String get_res_metadata_dir() {
+ return _GodotSharpDirs::get_singleton().res_metadata_dir;
+}
+
+String get_res_assemblies_dir() {
+ return _GodotSharpDirs::get_singleton().res_assemblies_dir;
+}
+
+String get_res_config_dir() {
+ return _GodotSharpDirs::get_singleton().res_config_dir;
+}
+
+String get_res_temp_dir() {
+ return _GodotSharpDirs::get_singleton().res_temp_dir;
+}
+
+String get_res_temp_assemblies_base_dir() {
+ return _GodotSharpDirs::get_singleton().res_temp_assemblies_base_dir;
+}
+
+String get_res_temp_assemblies_dir() {
+ return _GodotSharpDirs::get_singleton().res_temp_assemblies_dir;
+}
+
+String get_mono_user_dir() {
+ return _GodotSharpDirs::get_singleton().mono_user_dir;
+}
+
+String get_mono_logs_dir() {
+ return _GodotSharpDirs::get_singleton().mono_logs_dir;
+}
+
+#ifdef TOOLS_ENABLED
+String get_mono_solutions_dir() {
+ return _GodotSharpDirs::get_singleton().mono_solutions_dir;
+}
+
+String get_build_logs_dir() {
+ return _GodotSharpDirs::get_singleton().build_logs_dir;
+}
+
+String get_project_sln_path() {
+ return _GodotSharpDirs::get_singleton().sln_filepath;
+}
+
+String get_project_csproj_path() {
+ return _GodotSharpDirs::get_singleton().csproj_filepath;
+}
+#endif
+}
diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h
new file mode 100644
index 0000000000..ba2c065210
--- /dev/null
+++ b/modules/mono/godotsharp_dirs.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* godotsharp_dirs.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GODOTSHARP_DIRS_H
+#define GODOTSHARP_DIRS_H
+
+#include "ustring.h"
+
+namespace GodotSharpDirs {
+
+String get_res_data_dir();
+String get_res_metadata_dir();
+String get_res_assemblies_dir();
+String get_res_config_dir();
+String get_res_temp_dir();
+String get_res_temp_assemblies_base_dir();
+String get_res_temp_assemblies_dir();
+
+String get_mono_user_dir();
+String get_mono_logs_dir();
+
+#ifdef TOOLS_ENABLED
+String get_mono_solutions_dir();
+String get_build_logs_dir();
+String get_custom_project_settings_dir();
+#endif
+
+String get_project_sln_path();
+String get_project_csproj_path();
+}
+
+#endif // GODOTSHARP_DIRS_H
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
new file mode 100644
index 0000000000..e10e06df0e
--- /dev/null
+++ b/modules/mono/mono_gc_handle.cpp
@@ -0,0 +1,81 @@
+/*************************************************************************/
+/* mono_gc_handle.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "mono_gc_handle.h"
+
+#include "mono_gd/gd_mono.h"
+
+uint32_t MonoGCHandle::make_strong_handle(MonoObject *p_object) {
+
+ return mono_gchandle_new(
+ p_object,
+ false /* do not pin the object */
+ );
+}
+
+uint32_t MonoGCHandle::make_weak_handle(MonoObject *p_object) {
+
+ return mono_gchandle_new_weakref(
+ p_object,
+ true /* track_resurrection: allows us to invoke _notification(NOTIFICATION_PREDELETE) while disposing */
+ );
+}
+
+Ref<MonoGCHandle> MonoGCHandle::create_strong(MonoObject *p_object) {
+
+ return memnew(MonoGCHandle(make_strong_handle(p_object)));
+}
+
+Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) {
+
+ return memnew(MonoGCHandle(make_weak_handle(p_object)));
+}
+
+void MonoGCHandle::release() {
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(GDMono::get_singleton() == NULL);
+#endif
+
+ if (!released && GDMono::get_singleton()->is_runtime_initialized()) {
+ mono_gchandle_free(handle);
+ released = true;
+ }
+}
+
+MonoGCHandle::MonoGCHandle(uint32_t p_handle) {
+
+ released = false;
+ handle = p_handle;
+}
+
+MonoGCHandle::~MonoGCHandle() {
+
+ release();
+}
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
new file mode 100644
index 0000000000..cf5b6cec21
--- /dev/null
+++ b/modules/mono/mono_gc_handle.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* mono_gc_handle.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CSHARP_GC_HANDLE_H
+#define CSHARP_GC_HANDLE_H
+
+#include <mono/jit/jit.h>
+
+#include "reference.h"
+
+class MonoGCHandle : public Reference {
+
+ GDCLASS(MonoGCHandle, Reference)
+
+ bool released;
+ uint32_t handle;
+
+public:
+ static uint32_t make_strong_handle(MonoObject *p_object);
+ static uint32_t make_weak_handle(MonoObject *p_object);
+
+ static Ref<MonoGCHandle> create_strong(MonoObject *p_object);
+ static Ref<MonoGCHandle> create_weak(MonoObject *p_object);
+
+ _FORCE_INLINE_ MonoObject *get_target() const { return released ? NULL : mono_gchandle_get_target(handle); }
+
+ _FORCE_INLINE_ void set_handle(uint32_t p_handle) {
+ handle = p_handle;
+ released = false;
+ }
+ void release();
+
+ MonoGCHandle(uint32_t p_handle);
+ ~MonoGCHandle();
+};
+
+#endif // CSHARP_GC_HANDLE_H
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
new file mode 100644
index 0000000000..c997b0f000
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -0,0 +1,784 @@
+/*************************************************************************/
+/* gd_mono.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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.h"
+
+#include <mono/metadata/exception.h>
+#include <mono/metadata/mono-config.h>
+#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/mono-gc.h>
+
+#include "os/dir_access.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "os/thread.h"
+#include "project_settings.h"
+
+#include "../csharp_script.h"
+#include "../utils/path_utils.h"
+#include "gd_mono_utils.h"
+
+#ifdef TOOLS_ENABLED
+#include "../editor/godotsharp_editor.h"
+#endif
+
+void gdmono_unhandled_exception_hook(MonoObject *exc, void *user_data) {
+
+ (void)user_data; // UNUSED
+
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ abort();
+}
+
+#ifdef MONO_PRINT_HANDLER_ENABLED
+void gdmono_MonoPrintCallback(const char *string, mono_bool is_stdout) {
+
+ if (is_stdout) {
+ OS::get_singleton()->print(string);
+ } else {
+ OS::get_singleton()->printerr(string);
+ }
+}
+#endif
+
+GDMono *GDMono::singleton = NULL;
+
+#ifdef DEBUG_ENABLED
+static bool _wait_for_debugger_msecs(uint32_t p_msecs) {
+
+ do {
+ if (mono_is_debugger_attached())
+ return true;
+
+ int last_tick = OS::get_singleton()->get_ticks_msec();
+
+ OS::get_singleton()->delay_usec((p_msecs < 25 ? p_msecs : 25) * 1000);
+
+ int tdiff = OS::get_singleton()->get_ticks_msec() - last_tick;
+
+ if (tdiff > p_msecs) {
+ p_msecs = 0;
+ } else {
+ p_msecs -= tdiff;
+ }
+ } while (p_msecs > 0);
+
+ return mono_is_debugger_attached();
+}
+#endif
+
+#ifdef TOOLS_ENABLED
+// temporary workaround. should be provided from Main::setup/setup2 instead
+bool _is_project_manager_requested() {
+
+ List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
+ for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) {
+ const String &arg = E->get();
+ if (arg == "-p" || arg == "--project-manager")
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+#ifdef DEBUG_ENABLED
+void gdmono_debug_init() {
+
+ mono_debug_init(MONO_DEBUG_FORMAT_MONO);
+
+ int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685);
+ bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
+ int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint() ||
+ ProjectSettings::get_singleton()->get_resource_path().empty() ||
+ _is_project_manager_requested()) {
+ return;
+ }
+#endif
+
+ CharString da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
+ ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
+ .utf8();
+ // --debugger-agent=help
+ const char *options[] = {
+ "--soft-breakpoints",
+ da_args.get_data()
+ };
+ mono_jit_parse_options(2, (char **)options);
+}
+#endif
+
+void GDMono::initialize() {
+
+ ERR_FAIL_NULL(Engine::get_singleton());
+
+ OS::get_singleton()->print("Mono: Initializing module...\n");
+
+#ifdef DEBUG_METHODS_ENABLED
+ _initialize_and_check_api_hashes();
+#endif
+
+ GDMonoLog::get_singleton()->initialize();
+
+#ifdef MONO_PRINT_HANDLER_ENABLED
+ mono_trace_set_print_handler(gdmono_MonoPrintCallback);
+ mono_trace_set_printerr_handler(gdmono_MonoPrintCallback);
+#endif
+
+#ifdef WINDOWS_ENABLED
+ mono_reg_info = MonoRegUtils::find_mono();
+
+ CharString assembly_dir;
+ CharString config_dir;
+
+ if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
+ assembly_dir = mono_reg_info.assembly_dir.utf8();
+ }
+
+ if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
+ config_dir = mono_reg_info.config_dir.utf8();
+ }
+
+ mono_set_dirs(assembly_dir.length() ? assembly_dir.get_data() : NULL,
+ config_dir.length() ? config_dir.get_data() : NULL);
+#else
+ mono_set_dirs(NULL, NULL);
+#endif
+
+ GDMonoAssembly::initialize();
+
+#ifdef DEBUG_ENABLED
+ gdmono_debug_init();
+#endif
+
+ mono_config_parse(NULL);
+
+ root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
+
+ ERR_EXPLAIN("Mono: Failed to initialize runtime");
+ ERR_FAIL_NULL(root_domain);
+
+ GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread());
+
+ runtime_initialized = true;
+
+ OS::get_singleton()->print("Mono: Runtime initialized\n");
+
+ // mscorlib assembly MUST be present at initialization
+ ERR_EXPLAIN("Mono: Failed to load mscorlib assembly");
+ ERR_FAIL_COND(!_load_corlib_assembly());
+
+#ifdef TOOLS_ENABLED
+ // The tools domain must be loaded here, before the scripts domain.
+ // Otherwise domain unload on the scripts domain will hang indefinitely.
+
+ ERR_EXPLAIN("Mono: Failed to load tools domain");
+ ERR_FAIL_COND(_load_tools_domain() != OK);
+
+ // TODO move to editor init callback, and do it lazily when required before editor init (e.g.: bindings generation)
+ ERR_EXPLAIN("Mono: Failed to load Editor Tools assembly");
+ ERR_FAIL_COND(!_load_editor_tools_assembly());
+#endif
+
+ ERR_EXPLAIN("Mono: Failed to load scripts domain");
+ ERR_FAIL_COND(_load_scripts_domain() != OK);
+
+#ifdef DEBUG_ENABLED
+ bool debugger_attached = _wait_for_debugger_msecs(500);
+ if (!debugger_attached && OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->printerr("Mono: Debugger wait timeout\n");
+#endif
+
+ _register_internal_calls();
+
+ // The following assemblies are not required at initialization
+ _load_all_script_assemblies();
+
+ mono_install_unhandled_exception_hook(gdmono_unhandled_exception_hook, NULL);
+
+ OS::get_singleton()->print("Mono: ALL IS GOOD\n");
+}
+
+#ifndef MONO_GLUE_DISABLED
+namespace GodotSharpBindings {
+
+uint64_t get_core_api_hash();
+uint64_t get_editor_api_hash();
+
+void register_generated_icalls();
+} // namespace GodotSharpBindings
+#endif
+
+void GDMono::_register_internal_calls() {
+#ifndef MONO_GLUE_DISABLED
+ GodotSharpBindings::register_generated_icalls();
+#endif
+
+#ifdef TOOLS_ENABLED
+ GodotSharpBuilds::_register_internal_calls();
+#endif
+}
+
+#ifdef DEBUG_METHODS_ENABLED
+void GDMono::_initialize_and_check_api_hashes() {
+
+ api_core_hash = ClassDB::get_api_hash(ClassDB::API_CORE);
+
+#ifndef MONO_GLUE_DISABLED
+ if (api_core_hash != GodotSharpBindings::get_core_api_hash()) {
+ ERR_PRINT("Mono: Core API hash mismatch!");
+ }
+#endif
+
+#ifdef TOOLS_ENABLED
+ api_editor_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR);
+
+#ifndef MONO_GLUE_DISABLED
+ if (api_editor_hash != GodotSharpBindings::get_editor_api_hash()) {
+ ERR_PRINT("Mono: Editor API hash mismatch!");
+ }
+#endif
+
+#endif // TOOLS_ENABLED
+}
+#endif // DEBUG_METHODS_ENABLED
+
+void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
+
+ assemblies[p_domain_id][p_assembly->get_name()] = p_assembly;
+}
+
+GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
+
+ MonoDomain *domain = mono_domain_get();
+ uint32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
+ return assemblies[domain_id].getptr(p_name);
+}
+
+bool GDMono::_load_assembly(const String &p_name, GDMonoAssembly **r_assembly) {
+
+ CRASH_COND(!r_assembly);
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + "...\n").utf8());
+
+ MonoImageOpenStatus status = MONO_IMAGE_OK;
+ MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
+ MonoAssembly *assembly = mono_assembly_load_full(aname, NULL, &status, false);
+ mono_assembly_name_free(aname);
+
+ if (!assembly)
+ return false;
+
+ uint32_t domain_id = mono_domain_get_id(mono_domain_get());
+
+ GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
+
+ ERR_FAIL_COND_V(status != MONO_IMAGE_OK, false);
+ ERR_FAIL_COND_V(stored_assembly == NULL, false);
+
+ ERR_FAIL_COND_V((*stored_assembly)->get_assembly() != assembly, false);
+ *r_assembly = *stored_assembly;
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print(String("Mono: Assembly " + p_name + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
+
+ return true;
+}
+
+bool GDMono::_load_corlib_assembly() {
+
+ if (corlib_assembly)
+ return true;
+
+ bool success = _load_assembly("mscorlib", &corlib_assembly);
+
+ if (success)
+ GDMonoUtils::update_corlib_cache();
+
+ return success;
+}
+
+bool GDMono::_load_core_api_assembly() {
+
+ if (api_assembly)
+ return true;
+
+ bool success = _load_assembly(API_ASSEMBLY_NAME, &api_assembly);
+
+ if (success)
+ GDMonoUtils::update_godot_api_cache();
+
+ return success;
+}
+
+#ifdef TOOLS_ENABLED
+bool GDMono::_load_editor_api_assembly() {
+
+ if (editor_api_assembly)
+ return true;
+
+ return _load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly);
+}
+#endif
+
+#ifdef TOOLS_ENABLED
+bool GDMono::_load_editor_tools_assembly() {
+
+ if (editor_tools_assembly)
+ return true;
+
+ _GDMONO_SCOPE_DOMAIN_(tools_domain)
+
+ return _load_assembly(EDITOR_TOOLS_ASSEMBLY_NAME, &editor_tools_assembly);
+}
+#endif
+
+bool GDMono::_load_project_assembly() {
+
+ if (project_assembly)
+ return true;
+
+ String name = ProjectSettings::get_singleton()->get("application/config/name");
+ if (name.empty()) {
+ name = "UnnamedProject";
+ }
+
+ bool success = _load_assembly(name, &project_assembly);
+
+ if (success)
+ mono_assembly_set_main(project_assembly->get_assembly());
+
+ return success;
+}
+
+bool GDMono::_load_all_script_assemblies() {
+
+#ifndef MONO_GLUE_DISABLED
+ if (!_load_core_api_assembly()) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->printerr("Mono: Failed to load Core API assembly\n");
+ return false;
+ } else {
+#ifdef TOOLS_ENABLED
+ if (!_load_editor_api_assembly()) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->printerr("Mono: Failed to load Editor API assembly\n");
+ return false;
+ }
+#endif
+ }
+
+ if (!_load_project_assembly()) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->printerr("Mono: Failed to load project assembly\n");
+ return false;
+ }
+
+ return true;
+#else
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print("Mono: Glue disbled, ignoring script assemblies\n");
+
+ return true;
+#endif
+}
+
+Error GDMono::_load_scripts_domain() {
+
+ ERR_FAIL_COND_V(scripts_domain != NULL, ERR_BUG);
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Mono: Loading scripts domain...\n");
+ }
+
+ scripts_domain = GDMonoUtils::create_domain("GodotEngine.ScriptsDomain");
+
+ ERR_EXPLAIN("Mono: Could not create scripts app domain");
+ ERR_FAIL_NULL_V(scripts_domain, ERR_CANT_CREATE);
+
+ mono_domain_set(scripts_domain, true);
+
+ return OK;
+}
+
+Error GDMono::_unload_scripts_domain() {
+
+ ERR_FAIL_NULL_V(scripts_domain, ERR_BUG);
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Mono: Unloading scripts domain...\n");
+ }
+
+ _GodotSharp::get_singleton()->_dispose_callback();
+
+ if (mono_domain_get() != root_domain)
+ mono_domain_set(root_domain, true);
+
+ mono_gc_collect(mono_gc_max_generation());
+
+ finalizing_scripts_domain = true;
+ mono_domain_finalize(scripts_domain, 2000);
+ finalizing_scripts_domain = false;
+
+ mono_gc_collect(mono_gc_max_generation());
+
+ _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
+
+ api_assembly = NULL;
+ project_assembly = NULL;
+#ifdef TOOLS_ENABLED
+ editor_api_assembly = NULL;
+#endif
+
+ MonoDomain *domain = scripts_domain;
+ scripts_domain = NULL;
+
+ _GodotSharp::get_singleton()->_dispose_callback();
+
+ MonoObject *ex = NULL;
+ mono_domain_try_unload(domain, &ex);
+
+ if (ex) {
+ ERR_PRINT("Exception thrown when unloading scripts domain:");
+ mono_print_unhandled_exception(ex);
+ return FAILED;
+ }
+
+ return OK;
+}
+
+#ifdef TOOLS_ENABLED
+Error GDMono::_load_tools_domain() {
+
+ ERR_FAIL_COND_V(tools_domain != NULL, ERR_BUG);
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Mono: Loading tools domain...\n");
+ }
+
+ tools_domain = GDMonoUtils::create_domain("GodotEngine.ToolsDomain");
+
+ ERR_EXPLAIN("Mono: Could not create tools app domain");
+ ERR_FAIL_NULL_V(tools_domain, ERR_CANT_CREATE);
+
+ return OK;
+}
+#endif
+
+#ifdef TOOLS_ENABLED
+Error GDMono::reload_scripts_domain() {
+
+ ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG);
+
+ if (scripts_domain) {
+ Error err = _unload_scripts_domain();
+ if (err != OK) {
+ ERR_PRINT("Mono: Failed to unload scripts domain");
+ return err;
+ }
+ }
+
+ Error err = _load_scripts_domain();
+ if (err != OK) {
+ ERR_PRINT("Mono: Failed to load scripts domain");
+ return err;
+ }
+
+ if (!_load_all_script_assemblies()) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->printerr("Mono: Failed to load script assemblies\n");
+ return ERR_CANT_OPEN;
+ }
+
+ return OK;
+}
+#endif
+
+GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
+
+ MonoImage *image = mono_class_get_image(p_raw_class);
+
+ if (image == corlib_assembly->get_image())
+ return corlib_assembly->get_class(p_raw_class);
+
+ uint32_t domain_id = mono_domain_get_id(mono_domain_get());
+ HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
+
+ const String *k = NULL;
+ while ((k = domain_assemblies.next(k))) {
+ GDMonoAssembly *assembly = domain_assemblies.get(*k);
+ if (assembly->get_image() == image) {
+ GDMonoClass *klass = assembly->get_class(p_raw_class);
+
+ if (klass)
+ return klass;
+ }
+ }
+
+ return NULL;
+}
+
+void GDMono::_domain_assemblies_cleanup(uint32_t p_domain_id) {
+
+ HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
+
+ const String *k = NULL;
+ while ((k = domain_assemblies.next(k))) {
+ memdelete(domain_assemblies.get(*k));
+ }
+
+ assemblies.erase(p_domain_id);
+}
+
+GDMono::GDMono() {
+
+ singleton = this;
+
+ gdmono_log = memnew(GDMonoLog);
+
+ runtime_initialized = false;
+ finalizing_scripts_domain = false;
+
+ root_domain = NULL;
+ scripts_domain = NULL;
+#ifdef TOOLS_ENABLED
+ tools_domain = NULL;
+#endif
+
+ corlib_assembly = NULL;
+ api_assembly = NULL;
+ project_assembly = NULL;
+#ifdef TOOLS_ENABLED
+ editor_api_assembly = NULL;
+ editor_tools_assembly = NULL;
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
+ api_core_hash = 0;
+#ifdef TOOLS_ENABLED
+ api_editor_hash = 0;
+#endif
+#endif
+}
+
+GDMono::~GDMono() {
+
+ if (runtime_initialized) {
+
+ if (scripts_domain) {
+
+ Error err = _unload_scripts_domain();
+ if (err != OK) {
+ WARN_PRINT("Mono: Failed to unload scripts domain");
+ }
+ }
+
+ const uint32_t *k = NULL;
+ while ((k = assemblies.next(k))) {
+ HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k);
+
+ const String *kk = NULL;
+ while ((kk = domain_assemblies.next(kk))) {
+ memdelete(domain_assemblies.get(*kk));
+ }
+ }
+ assemblies.clear();
+
+ GDMonoUtils::clear_cache();
+
+ OS::get_singleton()->print("Mono: Runtime cleanup...\n");
+
+ runtime_initialized = false;
+ mono_jit_cleanup(root_domain);
+ }
+
+ if (gdmono_log)
+ memdelete(gdmono_log);
+
+ singleton = NULL;
+}
+
+_GodotSharp *_GodotSharp::singleton = NULL;
+
+void _GodotSharp::_dispose_object(Object *p_object) {
+
+ if (p_object->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_object->get_script_instance());
+ if (cs_instance) {
+ cs_instance->mono_object_disposed();
+ return;
+ }
+ }
+
+ // Unsafe refcount decrement. The managed instance also counts as a reference.
+ // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
+ if (Object::cast_to<Reference>(p_object)->unreference()) {
+ memdelete(p_object);
+ }
+}
+
+void _GodotSharp::_dispose_callback() {
+
+#ifndef NO_THREADS
+ queue_mutex->lock();
+#endif
+
+ for (List<Object *>::Element *E = obj_delete_queue.front(); E; E = E->next()) {
+ _dispose_object(E->get());
+ }
+
+ for (List<NodePath *>::Element *E = np_delete_queue.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+
+ for (List<RID *>::Element *E = rid_delete_queue.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
+
+ obj_delete_queue.clear();
+ np_delete_queue.clear();
+ rid_delete_queue.clear();
+ queue_empty = true;
+
+#ifndef NO_THREADS
+ queue_mutex->unlock();
+#endif
+}
+
+void _GodotSharp::attach_thread() {
+
+ GDMonoUtils::attach_current_thread();
+}
+
+void _GodotSharp::detach_thread() {
+
+ GDMonoUtils::detach_current_thread();
+}
+
+bool _GodotSharp::is_finalizing_domain() {
+
+ return GDMono::get_singleton()->is_finalizing_scripts_domain();
+}
+
+bool _GodotSharp::is_domain_loaded() {
+
+ return GDMono::get_singleton()->get_scripts_domain() != NULL;
+}
+
+#define ENQUEUE_FOR_DISPOSAL(m_queue, m_inst) \
+ m_queue.push_back(m_inst); \
+ if (queue_empty) { \
+ queue_empty = false; \
+ call_deferred("_dispose_callback"); \
+ }
+
+void _GodotSharp::queue_dispose(Object *p_object) {
+
+ if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ _dispose_object(p_object);
+ } else {
+#ifndef NO_THREADS
+ queue_mutex->lock();
+#endif
+
+ ENQUEUE_FOR_DISPOSAL(obj_delete_queue, p_object);
+
+#ifndef NO_THREADS
+ queue_mutex->unlock();
+#endif
+ }
+}
+
+void _GodotSharp::queue_dispose(NodePath *p_node_path) {
+
+ if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ memdelete(p_node_path);
+ } else {
+#ifndef NO_THREADS
+ queue_mutex->lock();
+#endif
+
+ ENQUEUE_FOR_DISPOSAL(np_delete_queue, p_node_path);
+
+#ifndef NO_THREADS
+ queue_mutex->unlock();
+#endif
+ }
+}
+
+void _GodotSharp::queue_dispose(RID *p_rid) {
+
+ if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) {
+ memdelete(p_rid);
+ } else {
+#ifndef NO_THREADS
+ queue_mutex->lock();
+#endif
+
+ ENQUEUE_FOR_DISPOSAL(rid_delete_queue, p_rid);
+
+#ifndef NO_THREADS
+ queue_mutex->unlock();
+#endif
+ }
+}
+
+void _GodotSharp::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("attach_thread"), &_GodotSharp::attach_thread);
+ ClassDB::bind_method(D_METHOD("detach_thread"), &_GodotSharp::detach_thread);
+
+ ClassDB::bind_method(D_METHOD("is_finalizing_domain"), &_GodotSharp::is_finalizing_domain);
+ ClassDB::bind_method(D_METHOD("is_domain_loaded"), &_GodotSharp::is_domain_loaded);
+
+ ClassDB::bind_method(D_METHOD("_dispose_callback"), &_GodotSharp::_dispose_callback);
+}
+
+_GodotSharp::_GodotSharp() {
+
+ singleton = this;
+ queue_empty = true;
+#ifndef NO_THREADS
+ queue_mutex = Mutex::create();
+#endif
+}
+
+_GodotSharp::~_GodotSharp() {
+
+ singleton = NULL;
+
+ if (queue_mutex) {
+ memdelete(queue_mutex);
+ }
+}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
new file mode 100644
index 0000000000..b188c0730a
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -0,0 +1,226 @@
+/*************************************************************************/
+/* gd_mono.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_H
+#define GD_MONO_H
+
+#include "../godotsharp_defs.h"
+#include "gd_mono_assembly.h"
+#include "gd_mono_log.h"
+
+#ifdef WINDOWS_ENABLED
+#include "../utils/mono_reg_utils.h"
+#endif
+
+#define SCRIPTS_DOMAIN GDMono::get_singleton()->get_scripts_domain()
+#ifdef TOOLS_ENABLED
+#define TOOLS_DOMAIN GDMono::get_singleton()->get_tools_domain()
+#endif
+
+class GDMono {
+
+ bool runtime_initialized;
+ bool finalizing_scripts_domain;
+
+ MonoDomain *root_domain;
+ MonoDomain *scripts_domain;
+#ifdef TOOLS_ENABLED
+ MonoDomain *tools_domain;
+#endif
+
+ GDMonoAssembly *corlib_assembly;
+ GDMonoAssembly *api_assembly;
+ GDMonoAssembly *project_assembly;
+#ifdef TOOLS_ENABLED
+ GDMonoAssembly *editor_api_assembly;
+ GDMonoAssembly *editor_tools_assembly;
+#endif
+
+ HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
+
+ void _domain_assemblies_cleanup(uint32_t p_domain_id);
+
+ bool _load_corlib_assembly();
+ bool _load_core_api_assembly();
+#ifdef TOOLS_ENABLED
+ bool _load_editor_api_assembly();
+ bool _load_editor_tools_assembly();
+#endif
+ bool _load_project_assembly();
+
+ bool _load_all_script_assemblies();
+
+ void _register_internal_calls();
+
+ Error _load_scripts_domain();
+ Error _unload_scripts_domain();
+
+#ifdef TOOLS_ENABLED
+ Error _load_tools_domain();
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
+ uint64_t api_core_hash;
+#ifdef TOOLS_ENABLED
+ uint64_t api_editor_hash;
+#endif
+ void _initialize_and_check_api_hashes();
+#endif
+
+ bool _load_assembly(const String &p_name, GDMonoAssembly **r_assembly);
+
+ GDMonoLog *gdmono_log;
+
+#ifdef WINDOWS_ENABLED
+ MonoRegInfo mono_reg_info;
+#endif
+
+protected:
+ static GDMono *singleton;
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ uint64_t get_api_core_hash() { return api_core_hash; }
+#ifdef TOOLS_ENABLED
+ uint64_t get_api_editor_hash() { return api_editor_hash; }
+#endif
+#endif
+
+ enum MemberVisibility {
+ PRIVATE,
+ PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM
+ INTERNAL, // ASSEMBLY
+ PROTECTED, // FAMILY
+ PUBLIC
+ };
+
+ static GDMono *get_singleton() { return singleton; }
+
+ // Do not use these, unless you know what you're doing
+ void add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly);
+ GDMonoAssembly **get_loaded_assembly(const String &p_name);
+
+ _FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized; }
+ _FORCE_INLINE_ bool is_finalizing_scripts_domain() const { return finalizing_scripts_domain; }
+
+ _FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
+#ifdef TOOLS_ENABLED
+ _FORCE_INLINE_ MonoDomain *get_tools_domain() { return tools_domain; }
+#endif
+
+ _FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_api_assembly() const { return api_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
+#ifdef TOOLS_ENABLED
+ _FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_editor_tools_assembly() const { return editor_tools_assembly; }
+#endif
+
+#ifdef WINDOWS_ENABLED
+ const MonoRegInfo &get_mono_reg_info() { return mono_reg_info; }
+#endif
+
+ GDMonoClass *get_class(MonoClass *p_raw_class);
+
+#ifdef TOOLS_ENABLED
+ Error reload_scripts_domain();
+#endif
+
+ void initialize();
+
+ GDMono();
+ ~GDMono();
+};
+
+class GDMonoScopeDomain {
+
+ MonoDomain *prev_domain;
+
+public:
+ GDMonoScopeDomain(MonoDomain *p_domain) {
+ MonoDomain *prev_domain = mono_domain_get();
+ if (prev_domain != p_domain) {
+ this->prev_domain = prev_domain;
+ mono_domain_set(p_domain, false);
+ } else {
+ this->prev_domain = NULL;
+ }
+ }
+
+ ~GDMonoScopeDomain() {
+ if (prev_domain)
+ mono_domain_set(prev_domain, false);
+ }
+};
+
+#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \
+ GDMonoScopeDomain __gdmono__scope__domain__(m_mono_domain); \
+ (void)__gdmono__scope__domain__;
+
+class _GodotSharp : public Object {
+ GDCLASS(_GodotSharp, Object)
+
+ friend class GDMono;
+
+ void _dispose_object(Object *p_object);
+
+ void _dispose_callback();
+
+ List<Object *> obj_delete_queue;
+ List<NodePath *> np_delete_queue;
+ List<RID *> rid_delete_queue;
+
+ bool queue_empty;
+
+#ifndef NO_THREADS
+ Mutex *queue_mutex;
+#endif
+
+protected:
+ static _GodotSharp *singleton;
+ static void _bind_methods();
+
+public:
+ static _GodotSharp *get_singleton() { return singleton; }
+
+ void attach_thread();
+ void detach_thread();
+
+ bool is_finalizing_domain();
+ bool is_domain_loaded();
+
+ void queue_dispose(Object *p_object);
+ void queue_dispose(NodePath *p_node_path);
+ void queue_dispose(RID *p_rid);
+
+ _GodotSharp();
+ ~_GodotSharp();
+};
+
+#endif // GD_MONO_H
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
new file mode 100644
index 0000000000..7dc7043eec
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -0,0 +1,359 @@
+/*************************************************************************/
+/* gd_mono_assembly.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_assembly.h"
+
+#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/tokentype.h>
+
+#include "list.h"
+#include "os/file_access.h"
+#include "os/os.h"
+
+#include "../godotsharp_dirs.h"
+#include "gd_mono_class.h"
+
+bool GDMonoAssembly::no_search = false;
+Vector<String> GDMonoAssembly::search_dirs;
+
+MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_data) {
+
+ (void)user_data; // UNUSED
+
+ String name = mono_assembly_name_get_name(aname);
+ bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
+
+ if (no_search)
+ return NULL;
+
+ GDMonoAssembly **loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
+ if (loaded_asm)
+ return (*loaded_asm)->get_assembly();
+
+ no_search = true; // Avoid the recursion madness
+
+ String path;
+ MonoAssembly *res = NULL;
+
+ for (int i = 0; i < search_dirs.size(); i++) {
+ const String &search_dir = search_dirs[i];
+
+ if (has_extension) {
+ path = search_dir.plus_file(name);
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name.get_basename(), path);
+ break;
+ }
+ } else {
+ path = search_dir.plus_file(name + ".dll");
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name, path);
+ break;
+ }
+
+ path = search_dir.plus_file(name + ".exe");
+ if (FileAccess::exists(path)) {
+ res = _load_assembly_from(name, path);
+ break;
+ }
+ }
+ }
+
+ no_search = false;
+
+ return res;
+}
+
+MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
+
+ (void)user_data; // UNUSED
+
+ if (search_dirs.empty()) {
+#ifdef TOOLS_DOMAIN
+ search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
+#endif
+ search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
+ search_dirs.push_back(OS::get_singleton()->get_resource_dir());
+ search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
+
+ const char *rootdir = mono_assembly_getrootdir();
+ if (rootdir) {
+ search_dirs.push_back(String(rootdir).plus_file("mono").plus_file("4.5"));
+ }
+
+ if (assemblies_path) {
+ while (*assemblies_path) {
+ search_dirs.push_back(*assemblies_path);
+ ++assemblies_path;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+MonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path) {
+
+ GDMonoAssembly *assembly = memnew(GDMonoAssembly(p_name, p_path));
+
+ MonoDomain *domain = mono_domain_get();
+
+ Error err = assembly->load(domain);
+
+ if (err != OK) {
+ memdelete(assembly);
+ ERR_FAIL_V(NULL);
+ }
+
+ GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, assembly);
+
+ return assembly->get_assembly();
+}
+
+void GDMonoAssembly::initialize() {
+
+ // TODO refonly as well?
+ mono_install_assembly_preload_hook(&GDMonoAssembly::_preload_hook, NULL);
+ mono_install_assembly_search_hook(&GDMonoAssembly::_search_hook, NULL);
+}
+
+Error GDMonoAssembly::load(MonoDomain *p_domain) {
+
+ ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
+
+ uint64_t last_modified_time = FileAccess::get_modified_time(path);
+
+ Vector<uint8_t> data = FileAccess::get_file_as_array(path);
+ ERR_FAIL_COND_V(data.empty(), ERR_FILE_CANT_READ);
+
+ String image_filename(path);
+
+ MonoImageOpenStatus status;
+
+ image = mono_image_open_from_data_with_name(
+ (char *)&data[0], data.size(),
+ true, &status, false,
+ image_filename.utf8().get_data());
+
+ ERR_FAIL_COND_V(status != MONO_IMAGE_OK || image == NULL, ERR_FILE_CANT_OPEN);
+
+#ifdef DEBUG_ENABLED
+ String pdb_path(path + ".pdb");
+
+ if (!FileAccess::exists(pdb_path)) {
+ pdb_path = path.get_basename() + ".pdb"; // without .dll
+
+ if (!FileAccess::exists(pdb_path))
+ goto no_pdb;
+ }
+
+ pdb_data.clear();
+ pdb_data = FileAccess::get_file_as_array(pdb_path);
+ mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size());
+
+no_pdb:
+
+#endif
+
+ assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, false);
+
+ ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
+
+ if (p_domain && mono_image_get_entry_point(image)) {
+ // TODO should this be removed? do we want to call main? what other effects does this have?
+ mono_jit_exec(p_domain, assembly, 0, NULL);
+ }
+
+ loaded = true;
+ modified_time = last_modified_time;
+
+ return OK;
+}
+
+Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) {
+
+ ERR_FAIL_COND_V(loaded, ERR_FILE_ALREADY_IN_USE);
+
+ assembly = mono_image_get_assembly(p_image);
+ ERR_FAIL_NULL_V(assembly, FAILED);
+
+ image = p_image;
+
+ mono_image_addref(image);
+
+ loaded = true;
+
+ return OK;
+}
+
+void GDMonoAssembly::unload() {
+
+ ERR_FAIL_COND(!loaded);
+
+#ifdef DEBUG_ENABLED
+ if (pdb_data.size()) {
+ mono_debug_close_image(image);
+ pdb_data.clear();
+ }
+#endif
+
+ for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) {
+ memdelete(E->value());
+ }
+
+ cached_classes.clear();
+ cached_raw.clear();
+
+ mono_image_close(image);
+
+ assembly = NULL;
+ image = NULL;
+ loaded = false;
+}
+
+GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) {
+
+ ERR_FAIL_COND_V(!loaded, NULL);
+
+ ClassKey key(p_namespace, p_name);
+
+ GDMonoClass **match = cached_classes.getptr(key);
+
+ if (match)
+ return *match;
+
+ MonoClass *mono_class = mono_class_from_name(image, String(p_namespace).utf8(), String(p_name).utf8());
+
+ if (!mono_class)
+ return NULL;
+
+ GDMonoClass *wrapped_class = memnew(GDMonoClass(p_namespace, p_name, mono_class, this));
+
+ cached_classes[key] = wrapped_class;
+ cached_raw[mono_class] = wrapped_class;
+
+ return wrapped_class;
+}
+
+GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
+
+ ERR_FAIL_COND_V(!loaded, NULL);
+
+ Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class);
+
+ if (match)
+ return match->value();
+
+ StringName namespace_name = mono_class_get_namespace(p_mono_class);
+ StringName class_name = mono_class_get_name(p_mono_class);
+
+ GDMonoClass *wrapped_class = memnew(GDMonoClass(namespace_name, class_name, p_mono_class, this));
+
+ cached_classes[ClassKey(namespace_name, class_name)] = wrapped_class;
+ cached_raw[p_mono_class] = wrapped_class;
+
+ return wrapped_class;
+}
+
+GDMonoClass *GDMonoAssembly::get_object_derived_class(const StringName &p_class) {
+
+ GDMonoClass *match = NULL;
+
+ if (gdobject_class_cache_updated) {
+ Map<StringName, GDMonoClass *>::Element *result = gdobject_class_cache.find(p_class);
+
+ if (result)
+ match = result->get();
+ } else {
+ List<GDMonoClass *> nested_classes;
+
+ int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
+
+ for (int i = 1; i < rows; i++) {
+ MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF);
+
+ if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class))
+ continue;
+
+ GDMonoClass *current = get_class(mono_class);
+
+ if (!current)
+ continue;
+
+ nested_classes.push_back(current);
+
+ if (!match && current->get_name() == p_class)
+ match = current;
+
+ while (!nested_classes.empty()) {
+ GDMonoClass *current_nested = nested_classes.front()->get();
+ nested_classes.pop_back();
+
+ void *iter = NULL;
+
+ while (true) {
+ MonoClass *raw_nested = mono_class_get_nested_types(current_nested->get_raw(), &iter);
+
+ if (!raw_nested)
+ break;
+
+ GDMonoClass *nested_class = get_class(raw_nested);
+
+ if (nested_class) {
+ gdobject_class_cache.insert(nested_class->get_name(), nested_class);
+ nested_classes.push_back(nested_class);
+ }
+ }
+ }
+
+ gdobject_class_cache.insert(current->get_name(), current);
+ }
+
+ gdobject_class_cache_updated = true;
+ }
+
+ return match;
+}
+
+GDMonoAssembly::GDMonoAssembly(const String &p_name, const String &p_path) {
+
+ loaded = false;
+ gdobject_class_cache_updated = false;
+ name = p_name;
+ path = p_path;
+ modified_time = 0;
+ assembly = NULL;
+ image = NULL;
+}
+
+GDMonoAssembly::~GDMonoAssembly() {
+
+ if (loaded)
+ unload();
+}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
new file mode 100644
index 0000000000..710b674622
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -0,0 +1,121 @@
+/*************************************************************************/
+/* gd_mono_assembly.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_ASSEMBLY_H
+#define GD_MONO_ASSEMBLY_H
+
+#include <mono/jit/jit.h>
+#include <mono/metadata/assembly.h>
+
+#include "gd_mono_utils.h"
+#include "hash_map.h"
+#include "map.h"
+#include "ustring.h"
+
+class GDMonoAssembly {
+
+ struct ClassKey {
+ struct Hasher {
+ static _FORCE_INLINE_ uint32_t hash(const ClassKey &p_key) {
+ uint32_t hash = 0;
+
+ GDMonoUtils::hash_combine(hash, p_key.namespace_name.hash());
+ GDMonoUtils::hash_combine(hash, p_key.class_name.hash());
+
+ return hash;
+ }
+ };
+
+ _FORCE_INLINE_ bool operator==(const ClassKey &p_a) const {
+ return p_a.class_name == class_name && p_a.namespace_name == namespace_name;
+ }
+
+ ClassKey() {}
+
+ ClassKey(const StringName &p_namespace_name, const StringName &p_class_name) {
+ namespace_name = p_namespace_name;
+ class_name = p_class_name;
+ }
+
+ StringName namespace_name;
+ StringName class_name;
+ };
+
+ MonoAssembly *assembly;
+ MonoImage *image;
+
+ bool loaded;
+
+ String name;
+ String path;
+ uint64_t modified_time;
+
+ HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
+ Map<MonoClass *, GDMonoClass *> cached_raw;
+
+ bool gdobject_class_cache_updated;
+ Map<StringName, GDMonoClass *> gdobject_class_cache;
+
+#ifdef DEBUG_ENABLED
+ Vector<uint8_t> pdb_data;
+#endif
+
+ static bool no_search;
+ static Vector<String> search_dirs;
+
+ static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data);
+ static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
+
+ static MonoAssembly *_load_assembly_from(const String &p_name, const String &p_path);
+
+ friend class GDMono;
+ static void initialize();
+
+public:
+ Error load(MonoDomain *p_domain);
+ Error wrapper_for_image(MonoImage *p_image);
+ void unload();
+
+ _FORCE_INLINE_ bool is_loaded() const { return loaded; }
+ _FORCE_INLINE_ MonoImage *get_image() const { return image; }
+ _FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; }
+ _FORCE_INLINE_ String get_name() const { return name; }
+ _FORCE_INLINE_ String get_path() const { return path; }
+ _FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; }
+
+ GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_class);
+ GDMonoClass *get_class(MonoClass *p_mono_class);
+
+ GDMonoClass *get_object_derived_class(const StringName &p_class);
+
+ GDMonoAssembly(const String &p_name, const String &p_path = String());
+ ~GDMonoAssembly();
+};
+
+#endif // GD_MONO_ASSEMBLY_H
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
new file mode 100644
index 0000000000..77ba0ee90e
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -0,0 +1,413 @@
+/*************************************************************************/
+/* gd_mono_class.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_class.h"
+
+#include <mono/metadata/attrdefs.h>
+
+#include "gd_mono_assembly.h"
+
+MonoType *GDMonoClass::get_raw_type(GDMonoClass *p_class) {
+
+ return mono_class_get_type(p_class->get_raw());
+}
+
+bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
+
+ return mono_class_is_assignable_from(mono_class, p_from->mono_class);
+}
+
+String GDMonoClass::get_full_name() const {
+
+ String res = namespace_name;
+ if (res.length())
+ res += ".";
+ return res + class_name;
+}
+
+GDMonoClass *GDMonoClass::get_parent_class() {
+
+ if (assembly) {
+ MonoClass *parent_mono_class = mono_class_get_parent(mono_class);
+
+ if (parent_mono_class) {
+ return GDMono::get_singleton()->get_class(parent_mono_class);
+ }
+ }
+
+ return NULL;
+}
+
+#ifdef TOOLS_ENABLED
+Vector<MonoClassField *> GDMonoClass::get_enum_fields() {
+
+ bool class_is_enum = mono_class_is_enum(mono_class);
+ ERR_FAIL_COND_V(!class_is_enum, Vector<MonoClassField *>());
+
+ Vector<MonoClassField *> enum_fields;
+
+ void *iter = NULL;
+ MonoClassField *raw_field = NULL;
+ while ((raw_field = mono_class_get_fields(get_raw(), &iter)) != NULL) {
+ uint32_t field_flags = mono_field_get_flags(raw_field);
+
+ // Enums have an instance field named value__ which holds the value of the enum.
+ // Enum constants are static, so we will use this to ignore the value__ field.
+ if (field_flags & MONO_FIELD_ATTR_PUBLIC && field_flags & MONO_FIELD_ATTR_STATIC) {
+ enum_fields.push_back(raw_field);
+ }
+ }
+
+ return enum_fields;
+}
+#endif
+
+bool GDMonoClass::has_method(const StringName &p_name) {
+
+ return get_method(p_name) != NULL;
+}
+
+bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) {
+
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_NULL_V(p_attr_class, false);
+#endif
+
+ if (!attrs_fetched)
+ fetch_attributes();
+
+ if (!attributes)
+ return false;
+
+ return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
+}
+
+MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) {
+
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_NULL_V(p_attr_class, NULL);
+#endif
+
+ if (!attrs_fetched)
+ fetch_attributes();
+
+ if (!attributes)
+ return NULL;
+
+ return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
+}
+
+void GDMonoClass::fetch_attributes() {
+
+ ERR_FAIL_COND(attributes != NULL);
+
+ attributes = mono_custom_attrs_from_class(get_raw());
+ attrs_fetched = true;
+}
+
+void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) {
+
+ CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this));
+
+ if (methods_fetched)
+ return;
+
+ void *iter = NULL;
+ MonoMethod *raw_method = NULL;
+ while ((raw_method = mono_class_get_methods(get_raw(), &iter)) != NULL) {
+ StringName name = mono_method_get_name(raw_method);
+
+ GDMonoMethod *method = get_method(raw_method, name);
+ ERR_CONTINUE(!method);
+
+ if (method->get_name() != name) {
+
+#ifdef DEBUG_ENABLED
+ String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")";
+ WARN_PRINTS("Method `" + fullname + "` is hidden by Godot API method. Should be `" +
+ method->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`.");
+#endif
+ continue;
+ }
+
+#ifdef DEBUG_ENABLED
+ // For debug builds, we also fetched from native base classes as well before if this is not a native base class.
+ // This allows us to warn the user here if he is using snake_case by mistake.
+
+ if (p_native_base != this) {
+
+ GDMonoClass *native_top = p_native_base;
+ while (native_top) {
+ GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count());
+
+ if (m && m->get_name() != name) {
+ // found
+ String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")";
+ WARN_PRINTS("Method `" + fullname + "` should be `" + m->get_full_name_no_class() +
+ "`. In class `" + namespace_name + "." + class_name + "`.");
+ break;
+ }
+
+ if (native_top == CACHED_CLASS(GodotObject))
+ break;
+
+ native_top = native_top->get_parent_class();
+ }
+ }
+#endif
+
+ uint32_t flags = mono_method_get_flags(method->mono_method, NULL);
+
+ if (!(flags & MONO_METHOD_ATTR_VIRTUAL))
+ continue;
+
+ // Virtual method of Godot Object derived type, let's try to find GodotMethod attribute
+
+ GDMonoClass *top = p_native_base;
+
+ while (top) {
+ GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count());
+
+ if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) {
+ // Found base method with GodotMethod attribute.
+ // We get the original API method name from this attribute.
+ // This name must point to the virtual method.
+
+ MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute));
+
+ StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr);
+#ifdef DEBUG_ENABLED
+ CRASH_COND(godot_method_name == StringName());
+#endif
+ MethodKey key = MethodKey(godot_method_name, method->get_parameters_count());
+ GDMonoMethod **existing_method = methods.getptr(key);
+ if (existing_method)
+ memdelete(*existing_method); // Must delete old one
+ methods.set(key, method);
+
+ break;
+ }
+
+ if (top == CACHED_CLASS(GodotObject))
+ break;
+
+ top = top->get_parent_class();
+ }
+ }
+
+ methods_fetched = true;
+}
+
+GDMonoMethod *GDMonoClass::get_method(const StringName &p_name) {
+
+ ERR_FAIL_COND_V(!methods_fetched, NULL);
+
+ const MethodKey *k = NULL;
+
+ while ((k = methods.next(k))) {
+ if (k->name == p_name)
+ return methods.get(*k);
+ }
+
+ return NULL;
+}
+
+GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
+
+ MethodKey key = MethodKey(p_name, p_params_count);
+
+ GDMonoMethod **match = methods.getptr(key);
+
+ if (match)
+ return *match;
+
+ if (methods_fetched)
+ return NULL;
+
+ MonoMethod *raw_method = mono_class_get_method_from_name(mono_class, String(p_name).utf8().get_data(), p_params_count);
+
+ if (raw_method) {
+ GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method));
+ methods.set(key, method);
+
+ return method;
+ }
+
+ return NULL;
+}
+
+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);
+
+ return get_method(p_raw_method, method_name, params_count);
+}
+
+GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name) {
+
+ MonoMethodSignature *sig = mono_method_signature(p_raw_method);
+ int params_count = mono_signature_get_param_count(sig);
+ 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) {
+
+ ERR_FAIL_NULL_V(p_raw_method, NULL);
+
+ MethodKey key = MethodKey(p_name, p_params_count);
+
+ GDMonoMethod **match = methods.getptr(key);
+
+ if (match)
+ return *match;
+
+ GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method));
+ methods.set(key, method);
+
+ return method;
+}
+
+GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, bool p_include_namespace) {
+
+ MonoMethodDesc *desc = mono_method_desc_new(p_description.utf8().get_data(), p_include_namespace);
+ MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class);
+ mono_method_desc_free(desc);
+
+ return get_method(method);
+}
+
+GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
+
+ Map<StringName, GDMonoField *>::Element *result = fields.find(p_name);
+
+ if (result)
+ return result->value();
+
+ if (fields_fetched)
+ return NULL;
+
+ MonoClassField *raw_field = mono_class_get_field_from_name(mono_class, String(p_name).utf8().get_data());
+
+ if (raw_field) {
+ GDMonoField *field = memnew(GDMonoField(raw_field, this));
+ fields.insert(p_name, field);
+
+ return field;
+ }
+
+ return NULL;
+}
+
+const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
+
+ if (fields_fetched)
+ return fields_list;
+
+ void *iter = NULL;
+ MonoClassField *raw_field = NULL;
+ while ((raw_field = mono_class_get_fields(get_raw(), &iter)) != NULL) {
+ StringName name = mono_field_get_name(raw_field);
+
+ Map<StringName, GDMonoField *>::Element *match = fields.find(name);
+
+ if (match) {
+ fields_list.push_back(match->get());
+ } else {
+ GDMonoField *field = memnew(GDMonoField(raw_field, this));
+ fields.insert(name, field);
+ fields_list.push_back(field);
+ }
+ }
+
+ fields_fetched = true;
+
+ return fields_list;
+}
+
+GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) {
+
+ namespace_name = p_namespace;
+ class_name = p_name;
+ mono_class = p_class;
+ assembly = p_assembly;
+
+ attrs_fetched = false;
+ attributes = NULL;
+
+ methods_fetched = false;
+ fields_fetched = false;
+}
+
+GDMonoClass::~GDMonoClass() {
+
+ if (attributes) {
+ mono_custom_attrs_free(attributes);
+ }
+
+ for (Map<StringName, GDMonoField *>::Element *E = fields.front(); E; E = E->next()) {
+ memdelete(E->value());
+ }
+
+ {
+ // Ugly workaround...
+ // We may have duplicated values, because we redirect snake_case methods to PascalCasel (only Godot API methods).
+ // This way, we end with both the snake_case name and the PascalCasel name paired with the same method.
+ // Therefore, we must avoid deleting the same pointer twice.
+
+ int offset = 0;
+ Vector<GDMonoMethod *> deleted_methods;
+ deleted_methods.resize(methods.size());
+
+ const MethodKey *k = NULL;
+ while ((k = methods.next(k))) {
+ GDMonoMethod *method = methods.get(*k);
+
+ if (method) {
+ for (int i = 0; i < offset; i++) {
+ if (deleted_methods[i] == method) {
+ // Already deleted
+ goto already_deleted;
+ }
+ }
+
+ deleted_methods[offset] = method;
+ ++offset;
+
+ memdelete(method);
+ }
+
+ already_deleted:;
+ }
+
+ methods.clear();
+ }
+}
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
new file mode 100644
index 0000000000..ef1ca425a7
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -0,0 +1,130 @@
+/*************************************************************************/
+/* gd_mono_class.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_CLASS_H
+#define GD_MONO_CLASS_H
+
+#include <mono/metadata/debug-helpers.h>
+
+#include "map.h"
+#include "ustring.h"
+
+#include "gd_mono_field.h"
+#include "gd_mono_header.h"
+#include "gd_mono_method.h"
+#include "gd_mono_utils.h"
+
+class GDMonoClass {
+ struct MethodKey {
+ struct Hasher {
+ static _FORCE_INLINE_ uint32_t hash(const MethodKey &p_key) {
+ uint32_t hash = 0;
+
+ GDMonoUtils::hash_combine(hash, p_key.name.hash());
+ GDMonoUtils::hash_combine(hash, HashMapHasherDefault::hash(p_key.params_count));
+
+ return hash;
+ }
+ };
+
+ _FORCE_INLINE_ bool operator==(const MethodKey &p_a) const {
+ return p_a.params_count == params_count && p_a.name == name;
+ }
+
+ MethodKey() {}
+
+ MethodKey(const StringName &p_name, int p_params_count) {
+ name = p_name;
+ params_count = p_params_count;
+ }
+
+ StringName name;
+ int params_count;
+ };
+
+ StringName namespace_name;
+ StringName class_name;
+
+ MonoClass *mono_class;
+ GDMonoAssembly *assembly;
+
+ bool attrs_fetched;
+ MonoCustomAttrInfo *attributes;
+
+ bool methods_fetched;
+ HashMap<MethodKey, GDMonoMethod *, MethodKey::Hasher> methods;
+
+ bool fields_fetched;
+ Map<StringName, GDMonoField *> fields;
+ Vector<GDMonoField *> fields_list;
+
+ friend class GDMonoAssembly;
+ GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
+
+public:
+ static MonoType *get_raw_type(GDMonoClass *p_class);
+
+ bool is_assignable_from(GDMonoClass *p_from) const;
+
+ _FORCE_INLINE_ StringName get_namespace() const { return namespace_name; }
+ _FORCE_INLINE_ StringName get_name() const { return class_name; }
+
+ _FORCE_INLINE_ MonoClass *get_raw() const { return mono_class; }
+ _FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
+
+ String get_full_name() const;
+
+ GDMonoClass *get_parent_class();
+
+#ifdef TOOLS_ENABLED
+ Vector<MonoClassField *> get_enum_fields();
+#endif
+
+ bool has_method(const StringName &p_name);
+
+ bool has_attribute(GDMonoClass *p_attr_class);
+ MonoObject *get_attribute(GDMonoClass *p_attr_class);
+
+ void fetch_attributes();
+ void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
+
+ GDMonoMethod *get_method(const StringName &p_name);
+ GDMonoMethod *get_method(const StringName &p_name, int p_params_count);
+ 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_with_desc(const String &p_description, bool p_includes_namespace);
+
+ GDMonoField *get_field(const StringName &p_name);
+ const Vector<GDMonoField *> &get_all_fields();
+
+ ~GDMonoClass();
+};
+
+#endif // GD_MONO_CLASS_H
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
new file mode 100644
index 0000000000..1643f8cfc5
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -0,0 +1,364 @@
+/*************************************************************************/
+/* gd_mono_field.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_field.h"
+
+#include <mono/metadata/attrdefs.h>
+
+#include "gd_mono_class.h"
+#include "gd_mono_marshal.h"
+
+void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
+ mono_field_set_value(p_object, mono_field, &p_ptr);
+}
+
+void GDMonoField::set_value(MonoObject *p_object, const Variant &p_value) {
+#define SET_FROM_STRUCT_AND_BREAK(m_type) \
+ { \
+ const m_type &val = p_value.operator m_type(); \
+ MARSHALLED_OUT(m_type, val, raw); \
+ mono_field_set_value(p_object, mono_field, raw); \
+ break; \
+ }
+
+#define SET_FROM_PRIMITIVE(m_type) \
+ { \
+ m_type val = p_value.operator m_type(); \
+ mono_field_set_value(p_object, mono_field, &val); \
+ break; \
+ }
+
+#define SET_FROM_ARRAY_AND_BREAK(m_type) \
+ { \
+ MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator m_type()); \
+ mono_field_set_value(p_object, mono_field, &managed); \
+ break; \
+ }
+
+ switch (type.type_encoding) {
+ case MONO_TYPE_BOOLEAN: {
+ SET_FROM_PRIMITIVE(bool);
+ } break;
+
+ case MONO_TYPE_I1: {
+ SET_FROM_PRIMITIVE(signed char);
+ } break;
+ case MONO_TYPE_I2: {
+ SET_FROM_PRIMITIVE(signed short);
+ } break;
+ case MONO_TYPE_I4: {
+ SET_FROM_PRIMITIVE(signed int);
+ } break;
+ case MONO_TYPE_I8: {
+ SET_FROM_PRIMITIVE(int64_t);
+ } break;
+
+ case MONO_TYPE_U1: {
+ SET_FROM_PRIMITIVE(unsigned char);
+ } break;
+ case MONO_TYPE_U2: {
+ SET_FROM_PRIMITIVE(unsigned short);
+ } break;
+ case MONO_TYPE_U4: {
+ SET_FROM_PRIMITIVE(unsigned int);
+ } break;
+ case MONO_TYPE_U8: {
+ SET_FROM_PRIMITIVE(uint64_t);
+ } break;
+
+ case MONO_TYPE_R4: {
+ SET_FROM_PRIMITIVE(float);
+ } break;
+
+ case MONO_TYPE_R8: {
+ SET_FROM_PRIMITIVE(double);
+ } break;
+
+ case MONO_TYPE_STRING: {
+ 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_AND_BREAK(Vector2);
+
+ if (tclass == CACHED_CLASS(Rect2))
+ SET_FROM_STRUCT_AND_BREAK(Rect2);
+
+ if (tclass == CACHED_CLASS(Transform2D))
+ SET_FROM_STRUCT_AND_BREAK(Transform2D);
+
+ if (tclass == CACHED_CLASS(Vector3))
+ SET_FROM_STRUCT_AND_BREAK(Vector3);
+
+ if (tclass == CACHED_CLASS(Basis))
+ SET_FROM_STRUCT_AND_BREAK(Basis);
+
+ if (tclass == CACHED_CLASS(Quat))
+ SET_FROM_STRUCT_AND_BREAK(Quat);
+
+ if (tclass == CACHED_CLASS(Transform))
+ SET_FROM_STRUCT_AND_BREAK(Transform);
+
+ if (tclass == CACHED_CLASS(Rect3))
+ SET_FROM_STRUCT_AND_BREAK(Rect3);
+
+ if (tclass == CACHED_CLASS(Color))
+ SET_FROM_STRUCT_AND_BREAK(Color);
+
+ if (tclass == CACHED_CLASS(Plane))
+ SET_FROM_STRUCT_AND_BREAK(Plane);
+
+ if (mono_class_is_enum(tclass->get_raw()))
+ SET_FROM_PRIMITIVE(signed int);
+
+ ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
+ ERR_FAIL();
+ } break;
+
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY: {
+ MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class));
+
+ if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
+ SET_FROM_ARRAY_AND_BREAK(Array);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
+ SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
+ SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
+
+ if (array_type->eklass == REAL_T_MONOCLASS)
+ SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(String))
+ SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
+ SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
+ SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Color))
+ SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
+
+ ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
+ ERR_FAIL();
+ } 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 *());
+ 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;
+ }
+
+ ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
+ ERR_FAIL();
+ } break;
+
+ case MONO_TYPE_OBJECT: {
+ // Variant
+ switch (p_value.get_type()) {
+ case Variant::BOOL: {
+ SET_FROM_PRIMITIVE(bool);
+ } break;
+ case Variant::INT: {
+ SET_FROM_PRIMITIVE(int);
+ } break;
+ case Variant::REAL: {
+#ifdef REAL_T_IS_DOUBLE
+ SET_FROM_PRIMITIVE(double);
+#else
+ SET_FROM_PRIMITIVE(float);
+#endif
+ } break;
+ case Variant::STRING: {
+ MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
+ mono_field_set_value(p_object, mono_field, mono_string);
+ } break;
+ case Variant::VECTOR2: SET_FROM_STRUCT_AND_BREAK(Vector2);
+ case Variant::RECT2: SET_FROM_STRUCT_AND_BREAK(Rect2);
+ case Variant::VECTOR3: SET_FROM_STRUCT_AND_BREAK(Vector3);
+ case Variant::TRANSFORM2D: SET_FROM_STRUCT_AND_BREAK(Transform2D);
+ case Variant::PLANE: SET_FROM_STRUCT_AND_BREAK(Plane);
+ case Variant::QUAT: SET_FROM_STRUCT_AND_BREAK(Quat);
+ case Variant::RECT3: SET_FROM_STRUCT_AND_BREAK(Rect3);
+ case Variant::BASIS: SET_FROM_STRUCT_AND_BREAK(Basis);
+ case Variant::TRANSFORM: SET_FROM_STRUCT_AND_BREAK(Transform);
+ case Variant::COLOR: SET_FROM_STRUCT_AND_BREAK(Color);
+ case Variant::NODE_PATH: {
+ 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());
+ mono_field_set_value(p_object, mono_field, managed);
+ } break;
+ case Variant::OBJECT: {
+ MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+ case Variant::DICTIONARY: {
+ MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
+ mono_field_set_value(p_object, mono_field, managed);
+ } break;
+ case Variant::ARRAY: SET_FROM_ARRAY_AND_BREAK(Array);
+ case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
+ case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
+ case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
+ case Variant::POOL_STRING_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
+ case Variant::POOL_VECTOR2_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
+ case Variant::POOL_VECTOR3_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
+ case Variant::POOL_COLOR_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
+#undef SET_FROM_ARRAY_AND_BREAK
+ default: break;
+ }
+ } break;
+
+ case MONO_TYPE_GENERICINST: {
+ if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_raw()) {
+ MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary());
+ mono_field_set_value(p_object, mono_field, managed);
+ break;
+ }
+ } break;
+
+ default: {
+ ERR_PRINTS(String() + "Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding));
+ } break;
+ }
+
+#undef SET_FROM_STRUCT_AND_BREAK
+#undef SET_FROM_PRIMITIVE
+}
+
+bool GDMonoField::get_bool_value(MonoObject *p_object) {
+ return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
+}
+
+int GDMonoField::get_int_value(MonoObject *p_object) {
+ return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
+}
+
+String GDMonoField::get_string_value(MonoObject *p_object) {
+ MonoObject *val = get_value(p_object);
+ return val ? GDMonoMarshal::mono_string_to_godot((MonoString *)val) : String();
+}
+
+bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) {
+ ERR_FAIL_NULL_V(p_attr_class, false);
+
+ if (!attrs_fetched)
+ fetch_attributes();
+
+ if (!attributes)
+ return false;
+
+ return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
+}
+
+MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) {
+ ERR_FAIL_NULL_V(p_attr_class, NULL);
+
+ if (!attrs_fetched)
+ fetch_attributes();
+
+ if (!attributes)
+ return NULL;
+
+ return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
+}
+
+void GDMonoField::fetch_attributes() {
+ ERR_FAIL_COND(attributes != NULL);
+ attributes = mono_custom_attrs_from_field(owner->get_raw(), get_raw());
+ attrs_fetched = true;
+}
+
+bool GDMonoField::is_static() {
+ return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC;
+}
+
+GDMono::MemberVisibility GDMonoField::get_visibility() {
+ switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) {
+ case MONO_FIELD_ATTR_PRIVATE:
+ return GDMono::PRIVATE;
+ case MONO_FIELD_ATTR_FAM_AND_ASSEM:
+ return GDMono::PROTECTED_AND_INTERNAL;
+ case MONO_FIELD_ATTR_ASSEMBLY:
+ return GDMono::INTERNAL;
+ case MONO_FIELD_ATTR_FAMILY:
+ return GDMono::PROTECTED;
+ case MONO_FIELD_ATTR_PUBLIC:
+ return GDMono::PUBLIC;
+ default:
+ ERR_FAIL_V(GDMono::PRIVATE);
+ }
+}
+
+GDMonoField::GDMonoField(MonoClassField *p_raw_field, GDMonoClass *p_owner) {
+ owner = p_owner;
+ mono_field = p_raw_field;
+ name = 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);
+ type.type_class = GDMono::get_singleton()->get_class(field_type_class);
+
+ attrs_fetched = false;
+ attributes = NULL;
+}
+
+GDMonoField::~GDMonoField() {
+ if (attributes) {
+ mono_custom_attrs_free(attributes);
+ }
+}
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
new file mode 100644
index 0000000000..b7e1942d71
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -0,0 +1,74 @@
+/*************************************************************************/
+/* gd_mono_field.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GDMONOFIELD_H
+#define GDMONOFIELD_H
+
+#include "gd_mono.h"
+#include "gd_mono_header.h"
+
+class GDMonoField {
+ GDMonoClass *owner;
+ MonoClassField *mono_field;
+
+ String name;
+ ManagedType type;
+
+ bool attrs_fetched;
+ MonoCustomAttrInfo *attributes;
+
+public:
+ _FORCE_INLINE_ String get_name() const { return name; }
+ _FORCE_INLINE_ ManagedType get_type() const { return type; }
+
+ _FORCE_INLINE_ MonoClassField *get_raw() const { return mono_field; }
+
+ void set_value_raw(MonoObject *p_object, void *p_ptr);
+ void set_value(MonoObject *p_object, const Variant &p_value);
+
+ _FORCE_INLINE_ MonoObject *get_value(MonoObject *p_object) {
+ return mono_field_get_value_object(mono_domain_get(), mono_field, p_object);
+ }
+
+ bool get_bool_value(MonoObject *p_object);
+ int get_int_value(MonoObject *p_object);
+ String get_string_value(MonoObject *p_object);
+
+ bool has_attribute(GDMonoClass *p_attr_class);
+ MonoObject *get_attribute(GDMonoClass *p_attr_class);
+ void fetch_attributes();
+
+ bool is_static();
+ GDMono::MemberVisibility get_visibility();
+
+ GDMonoField(MonoClassField *p_raw_field, GDMonoClass *p_owner);
+ ~GDMonoField();
+};
+
+#endif // GDMONOFIELD_H
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
new file mode 100644
index 0000000000..803d394f96
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* gd_mono_header.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_HEADER_H
+#define GD_MONO_HEADER_H
+
+#include "int_types.h"
+
+class GDMonoAssembly;
+class GDMonoClass;
+class GDMonoMethod;
+class GDMonoField;
+
+struct ManagedType {
+ int type_encoding;
+ GDMonoClass *type_class;
+
+ ManagedType() {
+ type_class = 0;
+ }
+};
+
+typedef union {
+ uint32_t _uint32;
+ float _float;
+} mono_float;
+
+typedef union {
+ uint64_t _uint64;
+ float _double;
+} mono_double;
+
+#endif // GD_MONO_HEADER_H
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
new file mode 100644
index 0000000000..cfe2148b80
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_internals.cpp
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* godotsharp_internals.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_internals.h"
+
+#include "../csharp_script.h"
+#include "../mono_gc_handle.h"
+#include "gd_mono_utils.h"
+
+namespace GDMonoInternals {
+
+void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
+
+ // This method should not fail
+
+ CRASH_COND(!unmanaged);
+
+ // All mono objects created from the managed world (e.g.: `new Player()`)
+ // need to have a CSharpScript in order for their methods to be callable from the unmanaged side
+
+ Reference *ref = Object::cast_to<Reference>(unmanaged);
+
+ GDMonoClass *klass = GDMonoUtils::get_object_class(managed);
+
+ CRASH_COND(!klass);
+
+ Ref<MonoGCHandle> gchandle = ref ? MonoGCHandle::create_weak(managed) :
+ MonoGCHandle::create_strong(managed);
+
+ Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass);
+
+ CRASH_COND(script.is_null());
+
+ ScriptInstance *si = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
+
+ unmanaged->set_script_and_instance(script.get_ref_ptr(), si);
+
+ return;
+}
+}
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
new file mode 100644
index 0000000000..6bdf4a6c46
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_internals.h
@@ -0,0 +1,42 @@
+/*************************************************************************/
+/* godotsharp_internals.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_INTERNALS_H
+#define GD_MONO_INTERNALS_H
+
+#include <mono/jit/jit.h>
+
+#include "core/object.h"
+
+namespace GDMonoInternals {
+
+void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
+}
+
+#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
new file mode 100644
index 0000000000..e473348897
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -0,0 +1,175 @@
+/*************************************************************************/
+/* gd_mono_log.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_log.h"
+
+#include <mono/utils/mono-logger.h>
+#include <stdlib.h> // abort
+
+#include "os/dir_access.h"
+#include "os/os.h"
+
+#include "../godotsharp_dirs.h"
+
+static int log_level_get_id(const char *p_log_level) {
+
+ const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", NULL };
+
+ int i = 0;
+ while (valid_log_levels[i]) {
+ if (!strcmp(valid_log_levels[i], p_log_level))
+ return i;
+ i++;
+ }
+
+ return -1;
+}
+
+void gdmono_MonoLogCallback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
+
+ FileAccess *f = GDMonoLog::get_singleton()->get_log_file();
+
+ if (GDMonoLog::get_singleton()->get_log_level_id() >= log_level_get_id(log_level)) {
+ String text(message);
+ text += " (in domain ";
+ text += log_domain;
+ if (log_level) {
+ text += ", ";
+ text += log_level;
+ }
+ text += ")\n";
+
+ f->seek_end();
+ f->store_string(text);
+ }
+
+ if (fatal) {
+ ERR_PRINTS("Mono: FALTAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n");
+ abort();
+ }
+}
+
+GDMonoLog *GDMonoLog::singleton = NULL;
+
+bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
+
+ if (!DirAccess::exists(p_logs_dir)) {
+ DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(!diraccess, false);
+ Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir);
+ ERR_EXPLAIN("Failed to create mono logs directory");
+ ERR_FAIL_COND_V(logs_mkdir_err != OK, false);
+ }
+
+ return true;
+}
+
+void GDMonoLog::_open_log_file(const String &p_file_path) {
+
+ log_file = FileAccess::open(p_file_path, FileAccess::WRITE);
+
+ ERR_EXPLAIN("Failed to create log file");
+ ERR_FAIL_COND(!log_file);
+}
+
+void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
+
+ static const uint64_t MAX_SECS = 5 * 86400;
+
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND(!da);
+
+ Error err = da->change_dir(p_logs_dir);
+ ERR_FAIL_COND(err != OK);
+
+ ERR_FAIL_COND(da->list_dir_begin() != OK);
+
+ String current;
+ while ((current = da->get_next()).length()) {
+ if (da->current_is_dir())
+ continue;
+ if (!current.ends_with(".txt"))
+ continue;
+
+ String name = current.get_basename();
+ uint64_t unixtime = (uint64_t)name.to_int64();
+
+ if (OS::get_singleton()->get_unix_time() - unixtime > MAX_SECS) {
+ da->remove(current);
+ }
+ }
+
+ da->list_dir_end();
+}
+
+void GDMonoLog::initialize() {
+
+#ifdef DEBUG_ENABLED
+ const char *log_level = "debug";
+#else
+ const char *log_level = "warning";
+#endif
+
+ String logs_dir = GodotSharpDirs::get_mono_logs_dir();
+
+ if (_try_create_logs_dir(logs_dir)) {
+ _delete_old_log_files(logs_dir);
+
+ log_file_path = logs_dir.plus_file(String::num_int64(OS::get_singleton()->get_unix_time()) + ".txt");
+ _open_log_file(log_file_path);
+ }
+
+ mono_trace_set_level_string(log_level);
+ log_level_id = log_level_get_id(log_level);
+
+ if (log_file) {
+ if (OS::get_singleton()->is_stdout_verbose())
+ OS::get_singleton()->print(String("Mono: Logfile is " + log_file_path + "\n").utf8());
+ mono_trace_set_log_handler(gdmono_MonoLogCallback, this);
+ } else {
+ OS::get_singleton()->printerr("Mono: No log file, using default log handler\n");
+ }
+}
+
+GDMonoLog::GDMonoLog() {
+
+ singleton = this;
+
+ log_level_id = -1;
+}
+
+GDMonoLog::~GDMonoLog() {
+
+ singleton = NULL;
+
+ if (log_file) {
+ log_file->close();
+ memdelete(log_file);
+ }
+}
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
new file mode 100644
index 0000000000..497f1e5317
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* gd_mono_log.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_LOG_H
+#define GD_MONO_LOG_H
+
+#include "os/file_access.h"
+
+class GDMonoLog {
+
+ int log_level_id;
+
+ FileAccess *log_file;
+ String log_file_path;
+
+ bool _try_create_logs_dir(const String &p_logs_dir);
+ void _open_log_file(const String &p_file_path);
+ void _delete_old_log_files(const String &p_logs_dir);
+
+ static GDMonoLog *singleton;
+
+public:
+ _FORCE_INLINE_ static GDMonoLog *get_singleton() { return singleton; }
+
+ void initialize();
+
+ _FORCE_INLINE_ FileAccess *get_log_file() { return log_file; }
+ _FORCE_INLINE_ String get_log_file_path() { return log_file_path; }
+ _FORCE_INLINE_ int get_log_level_id() { return log_level_id; }
+
+ GDMonoLog();
+ ~GDMonoLog();
+};
+
+#endif // GD_MONO_LOG_H
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
new file mode 100644
index 0000000000..01392447f3
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -0,0 +1,859 @@
+/*************************************************************************/
+/* gd_mono_marshal.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_marshal.h"
+
+#include "gd_mono.h"
+#include "gd_mono_class.h"
+
+namespace GDMonoMarshal {
+
+#define RETURN_BOXED_STRUCT(m_t, m_var_in) \
+ { \
+ const m_t &m_in = m_var_in->operator m_t(); \
+ MARSHALLED_OUT(m_t, m_in, raw); \
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_t), raw); \
+ }
+
+#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \
+ { \
+ float *raw = (float *)mono_object_unbox(m_var_in); \
+ MARSHALLED_IN(m_t, raw, ret); \
+ return ret; \
+ }
+
+Variant::Type managed_to_variant_type(const ManagedType &p_type) {
+ switch (p_type.type_encoding) {
+ case MONO_TYPE_BOOLEAN:
+ return Variant::BOOL;
+
+ case MONO_TYPE_I1:
+ return Variant::INT;
+ case MONO_TYPE_I2:
+ return Variant::INT;
+ case MONO_TYPE_I4:
+ return Variant::INT;
+ case MONO_TYPE_I8:
+ return Variant::INT;
+
+ case MONO_TYPE_U1:
+ return Variant::INT;
+ case MONO_TYPE_U2:
+ return Variant::INT;
+ case MONO_TYPE_U4:
+ return Variant::INT;
+ case MONO_TYPE_U8:
+ return Variant::INT;
+
+ case MONO_TYPE_R4:
+ return Variant::REAL;
+ case MONO_TYPE_R8:
+ return Variant::REAL;
+
+ case MONO_TYPE_STRING: {
+ return Variant::STRING;
+ } break;
+
+ case MONO_TYPE_VALUETYPE: {
+ GDMonoClass *tclass = p_type.type_class;
+
+ if (tclass == CACHED_CLASS(Vector2))
+ return Variant::VECTOR2;
+
+ if (tclass == CACHED_CLASS(Rect2))
+ return Variant::RECT2;
+
+ if (tclass == CACHED_CLASS(Transform2D))
+ return Variant::TRANSFORM2D;
+
+ if (tclass == CACHED_CLASS(Vector3))
+ return Variant::VECTOR3;
+
+ if (tclass == CACHED_CLASS(Basis))
+ return Variant::BASIS;
+
+ if (tclass == CACHED_CLASS(Quat))
+ return Variant::QUAT;
+
+ if (tclass == CACHED_CLASS(Transform))
+ return Variant::TRANSFORM;
+
+ if (tclass == CACHED_CLASS(Rect3))
+ return Variant::RECT3;
+
+ if (tclass == CACHED_CLASS(Color))
+ return Variant::COLOR;
+
+ if (tclass == CACHED_CLASS(Plane))
+ return Variant::PLANE;
+
+ if (mono_class_is_enum(tclass->get_raw()))
+ return Variant::INT;
+ } break;
+
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY: {
+ MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+
+ if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
+ return Variant::ARRAY;
+
+ if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
+ return Variant::POOL_BYTE_ARRAY;
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
+ return Variant::POOL_INT_ARRAY;
+
+ if (array_type->eklass == REAL_T_MONOCLASS)
+ return Variant::POOL_REAL_ARRAY;
+
+ if (array_type->eklass == CACHED_CLASS_RAW(String))
+ return Variant::POOL_STRING_ARRAY;
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
+ return Variant::POOL_VECTOR2_ARRAY;
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
+ return Variant::POOL_VECTOR3_ARRAY;
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Color))
+ return Variant::POOL_COLOR_ARRAY;
+ } break;
+
+ case MONO_TYPE_CLASS: {
+ GDMonoClass *type_class = p_type.type_class;
+
+ // GodotObject
+ if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
+ return Variant::OBJECT;
+ }
+
+ if (CACHED_CLASS(NodePath) == type_class) {
+ return Variant::NODE_PATH;
+ }
+
+ if (CACHED_CLASS(RID) == type_class) {
+ return Variant::_RID;
+ }
+ } break;
+
+ case MONO_TYPE_GENERICINST: {
+ if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
+ return Variant::DICTIONARY;
+ }
+ } break;
+
+ default: {
+ } break;
+ }
+
+ // Unknown
+ return Variant::NIL;
+}
+
+String mono_to_utf8_string(MonoString *p_mono_string) {
+ MonoError error;
+ char *utf8 = mono_string_to_utf8_checked(p_mono_string, &error);
+
+ ERR_EXPLAIN("Conversion of MonoString to UTF8 failed.");
+ ERR_FAIL_COND_V(!mono_error_ok(&error), String());
+
+ String ret = String::utf8(utf8);
+
+ mono_free(utf8);
+
+ return ret;
+}
+
+String mono_to_utf16_string(MonoString *p_mono_string) {
+ int len = mono_string_length(p_mono_string);
+ String ret;
+
+ if (len == 0)
+ return ret;
+
+ ret.resize(len + 1);
+ ret.set(len, 0);
+
+ CharType *src = (CharType *)mono_string_chars(p_mono_string);
+ CharType *dst = &(ret.operator[](0));
+
+ for (int i = 0; i < len; i++) {
+ dst[i] = src[i];
+ }
+
+ return ret;
+}
+
+MonoObject *variant_to_mono_object(const Variant *p_var) {
+ ManagedType type;
+
+ type.type_encoding = MONO_TYPE_OBJECT;
+
+ return variant_to_mono_object(p_var, type);
+}
+
+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();
+ return BOX_BOOLEAN(val);
+ }
+
+ case MONO_TYPE_I1: {
+ char val = p_var->operator signed char();
+ return BOX_INT8(val);
+ }
+ case MONO_TYPE_I2: {
+ short val = p_var->operator signed short();
+ return BOX_INT16(val);
+ }
+ case MONO_TYPE_I4: {
+ int val = p_var->operator signed int();
+ return BOX_INT32(val);
+ }
+ case MONO_TYPE_I8: {
+ int64_t val = p_var->operator int64_t();
+ return BOX_INT64(val);
+ }
+
+ case MONO_TYPE_U1: {
+ char val = p_var->operator unsigned char();
+ return BOX_UINT8(val);
+ }
+ case MONO_TYPE_U2: {
+ short val = p_var->operator unsigned short();
+ return BOX_UINT16(val);
+ }
+ case MONO_TYPE_U4: {
+ int val = p_var->operator unsigned int();
+ return BOX_UINT32(val);
+ }
+ case MONO_TYPE_U8: {
+ uint64_t val = p_var->operator uint64_t();
+ return BOX_UINT64(val);
+ }
+
+ case MONO_TYPE_R4: {
+ float val = p_var->operator float();
+ return BOX_FLOAT(val);
+ }
+ case MONO_TYPE_R8: {
+ double val = p_var->operator double();
+ return BOX_DOUBLE(val);
+ }
+
+ case MONO_TYPE_STRING: {
+ return (MonoObject *)mono_string_from_godot(p_var->operator String());
+ } break;
+
+ case MONO_TYPE_VALUETYPE: {
+ GDMonoClass *tclass = p_type.type_class;
+
+ if (tclass == CACHED_CLASS(Vector2))
+ RETURN_BOXED_STRUCT(Vector2, p_var);
+
+ if (tclass == CACHED_CLASS(Rect2))
+ RETURN_BOXED_STRUCT(Rect2, p_var);
+
+ if (tclass == CACHED_CLASS(Transform2D))
+ RETURN_BOXED_STRUCT(Transform2D, p_var);
+
+ if (tclass == CACHED_CLASS(Vector3))
+ RETURN_BOXED_STRUCT(Vector3, p_var);
+
+ if (tclass == CACHED_CLASS(Basis))
+ RETURN_BOXED_STRUCT(Basis, p_var);
+
+ if (tclass == CACHED_CLASS(Quat))
+ RETURN_BOXED_STRUCT(Quat, p_var);
+
+ if (tclass == CACHED_CLASS(Transform))
+ RETURN_BOXED_STRUCT(Transform, p_var);
+
+ if (tclass == CACHED_CLASS(Rect3))
+ RETURN_BOXED_STRUCT(Rect3, p_var);
+
+ if (tclass == CACHED_CLASS(Color))
+ RETURN_BOXED_STRUCT(Color, p_var);
+
+ if (tclass == CACHED_CLASS(Plane))
+ RETURN_BOXED_STRUCT(Plane, p_var);
+
+ if (mono_class_is_enum(tclass->get_raw())) {
+ int val = p_var->operator signed int();
+ return BOX_ENUM(tclass->get_raw(), val);
+ }
+ } break;
+
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY: {
+ MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+
+ 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 *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
+ return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray());
+
+ if (array_type->eklass == REAL_T_MONOCLASS)
+ return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(String))
+ return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
+ return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
+ return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array());
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Color))
+ return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray());
+
+ ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
+ ERR_FAIL_V(NULL);
+ } 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(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());
+ }
+ } 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: {
+ int val = p_var->operator signed int();
+ return BOX_INT32(val);
+ }
+ case Variant::REAL: {
+#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:
+ RETURN_BOXED_STRUCT(Vector2, p_var);
+ case Variant::RECT2:
+ RETURN_BOXED_STRUCT(Rect2, p_var);
+ case Variant::VECTOR3:
+ RETURN_BOXED_STRUCT(Vector3, p_var);
+ case Variant::TRANSFORM2D:
+ RETURN_BOXED_STRUCT(Transform2D, p_var);
+ case Variant::PLANE:
+ RETURN_BOXED_STRUCT(Plane, p_var);
+ case Variant::QUAT:
+ RETURN_BOXED_STRUCT(Quat, p_var);
+ case Variant::RECT3:
+ RETURN_BOXED_STRUCT(Rect3, p_var);
+ case Variant::BASIS:
+ RETURN_BOXED_STRUCT(Basis, p_var);
+ case Variant::TRANSFORM:
+ RETURN_BOXED_STRUCT(Transform, p_var);
+ case Variant::COLOR:
+ RETURN_BOXED_STRUCT(Color, p_var);
+ 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::DICTIONARY:
+ return Dictionary_to_mono_object(p_var->operator Dictionary());
+ case Variant::ARRAY:
+ return (MonoObject *)Array_to_mono_array(p_var->operator Array());
+ case Variant::POOL_BYTE_ARRAY:
+ return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray());
+ case Variant::POOL_INT_ARRAY:
+ return (MonoObject *)PoolIntArray_to_mono_array(p_var->operator PoolIntArray());
+ case Variant::POOL_REAL_ARRAY:
+ return (MonoObject *)PoolRealArray_to_mono_array(p_var->operator PoolRealArray());
+ case Variant::POOL_STRING_ARRAY:
+ return (MonoObject *)PoolStringArray_to_mono_array(p_var->operator PoolStringArray());
+ case Variant::POOL_VECTOR2_ARRAY:
+ return (MonoObject *)PoolVector2Array_to_mono_array(p_var->operator PoolVector2Array());
+ case Variant::POOL_VECTOR3_ARRAY:
+ return (MonoObject *)PoolVector3Array_to_mono_array(p_var->operator PoolVector3Array());
+ case Variant::POOL_COLOR_ARRAY:
+ return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray());
+ default:
+ return NULL;
+ }
+ break;
+ case MONO_TYPE_GENERICINST: {
+ if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
+ return Dictionary_to_mono_object(p_var->operator Dictionary());
+ }
+ } break;
+ } break;
+ }
+
+ ERR_EXPLAIN(String() + "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(NULL);
+}
+
+Variant mono_object_to_variant(MonoObject *p_obj) {
+ if (!p_obj)
+ return Variant();
+
+ GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
+ ERR_FAIL_COND_V(!tclass, Variant());
+
+ MonoType *raw_type = tclass->get_raw_type(tclass);
+
+ ManagedType type;
+
+ type.type_encoding = mono_type_get_type(raw_type);
+ type.type_class = tclass;
+
+ return mono_object_to_variant(p_obj, type);
+}
+
+Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
+ switch (p_type.type_encoding) {
+ case MONO_TYPE_BOOLEAN:
+ return (bool)unbox<MonoBoolean>(p_obj);
+
+ case MONO_TYPE_I1:
+ return unbox<int8_t>(p_obj);
+ case MONO_TYPE_I2:
+ return unbox<int16_t>(p_obj);
+ case MONO_TYPE_I4:
+ 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:
+ return unbox<uint16_t>(p_obj);
+ case MONO_TYPE_U4:
+ 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: {
+ String str = mono_string_to_godot((MonoString *)p_obj);
+ return str;
+ } break;
+
+ case MONO_TYPE_VALUETYPE: {
+ GDMonoClass *tclass = p_type.type_class;
+
+ if (tclass == CACHED_CLASS(Vector2))
+ RETURN_UNBOXED_STRUCT(Vector2, p_obj);
+
+ if (tclass == CACHED_CLASS(Rect2))
+ RETURN_UNBOXED_STRUCT(Rect2, p_obj);
+
+ if (tclass == CACHED_CLASS(Transform2D))
+ RETURN_UNBOXED_STRUCT(Transform2D, p_obj);
+
+ if (tclass == CACHED_CLASS(Vector3))
+ RETURN_UNBOXED_STRUCT(Vector3, p_obj);
+
+ if (tclass == CACHED_CLASS(Basis))
+ RETURN_UNBOXED_STRUCT(Basis, p_obj);
+
+ if (tclass == CACHED_CLASS(Quat))
+ RETURN_UNBOXED_STRUCT(Quat, p_obj);
+
+ if (tclass == CACHED_CLASS(Transform))
+ RETURN_UNBOXED_STRUCT(Transform, p_obj);
+
+ if (tclass == CACHED_CLASS(Rect3))
+ RETURN_UNBOXED_STRUCT(Rect3, p_obj);
+
+ if (tclass == CACHED_CLASS(Color))
+ RETURN_UNBOXED_STRUCT(Color, p_obj);
+
+ if (tclass == CACHED_CLASS(Plane))
+ RETURN_UNBOXED_STRUCT(Plane, p_obj);
+
+ if (mono_class_is_enum(tclass->get_raw()))
+ return unbox<int32_t>(p_obj);
+ } break;
+
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY: {
+ MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class));
+
+ if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
+ return mono_array_to_Array((MonoArray *)p_obj);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
+ return mono_array_to_PoolByteArray((MonoArray *)p_obj);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
+ return mono_array_to_PoolIntArray((MonoArray *)p_obj);
+
+ if (array_type->eklass == REAL_T_MONOCLASS)
+ return mono_array_to_PoolRealArray((MonoArray *)p_obj);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(String))
+ return mono_array_to_PoolStringArray((MonoArray *)p_obj);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
+ return mono_array_to_PoolVector2Array((MonoArray *)p_obj);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
+ return mono_array_to_PoolVector3Array((MonoArray *)p_obj);
+
+ if (array_type->eklass == CACHED_CLASS_RAW(Color))
+ return mono_array_to_PoolColorArray((MonoArray *)p_obj);
+
+ ERR_EXPLAIN(String() + "Attempted to convert a managed array of unmarshallable element type to Variant.");
+ ERR_FAIL_V(Variant());
+ } break;
+
+ case MONO_TYPE_CLASS: {
+ GDMonoClass *type_class = p_type.type_class;
+
+ // GodotObject
+ if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
+ Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
+ return ptr ? Variant(ptr) : Variant();
+ }
+
+ if (CACHED_CLASS(NodePath) == type_class) {
+ NodePath *ptr = unbox<NodePath *>(CACHED_FIELD(NodePath, ptr)->get_value(p_obj));
+ return ptr ? Variant(*ptr) : Variant();
+ }
+
+ if (CACHED_CLASS(RID) == type_class) {
+ RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
+ return ptr ? Variant(*ptr) : Variant();
+ }
+ } break;
+
+ case MONO_TYPE_GENERICINST: {
+ if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_raw()) {
+ return mono_object_to_Dictionary(p_obj);
+ }
+ } break;
+ }
+
+ ERR_EXPLAIN(String() + "Attempted to convert an unmarshallable managed type to Variant. Name: \'" +
+ p_type.type_class->get_name() + "\' Encoding: " + itos(p_type.type_encoding));
+ ERR_FAIL_V(Variant());
+}
+
+MonoArray *Array_to_mono_array(const Array &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ MonoObject *boxed = variant_to_mono_object(p_array[i]);
+ mono_array_setref(ret, i, boxed);
+ }
+
+ return ret;
+}
+
+Array mono_array_to_Array(MonoArray *p_array) {
+ Array ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *elem = mono_array_get(p_array, MonoObject *, i);
+ ret.push_back(mono_object_to_variant(elem));
+ }
+
+ return ret;
+}
+
+// TODO Optimize reading/writing from/to PoolArrays
+
+MonoArray *PoolIntArray_to_mono_array(const PoolIntArray &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ mono_array_set(ret, int32_t, i, p_array[i]);
+ }
+
+ return ret;
+}
+
+PoolIntArray mono_array_to_PoolIntArray(MonoArray *p_array) {
+ PoolIntArray ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ int32_t elem = mono_array_get(p_array, int32_t, i);
+ ret.push_back(elem);
+ }
+
+ return ret;
+}
+
+MonoArray *PoolByteArray_to_mono_array(const PoolByteArray &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ mono_array_set(ret, uint8_t, i, p_array[i]);
+ }
+
+ return ret;
+}
+
+PoolByteArray mono_array_to_PoolByteArray(MonoArray *p_array) {
+ PoolByteArray ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ uint8_t elem = mono_array_get(p_array, uint8_t, i);
+ ret.push_back(elem);
+ }
+
+ return ret;
+}
+
+MonoArray *PoolRealArray_to_mono_array(const PoolRealArray &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), REAL_T_MONOCLASS, p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ mono_array_set(ret, real_t, i, p_array[i]);
+ }
+
+ return ret;
+}
+
+PoolRealArray mono_array_to_PoolRealArray(MonoArray *p_array) {
+ PoolRealArray ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ real_t elem = mono_array_get(p_array, real_t, i);
+ ret.push_back(elem);
+ }
+
+ return ret;
+}
+
+MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+ MonoString *boxed = mono_string_from_godot(p_array[i]);
+ mono_array_set(ret, MonoString *, i, boxed);
+ }
+
+ return ret;
+}
+
+PoolStringArray mono_array_to_PoolStringArray(MonoArray *p_array) {
+ PoolStringArray ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ MonoString *elem = mono_array_get(p_array, MonoString *, i);
+ ret.push_back(mono_string_to_godot(elem));
+ }
+
+ return ret;
+}
+
+MonoArray *PoolColorArray_to_mono_array(const PoolColorArray &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+#ifdef YOLOCOPY
+ mono_array_set(ret, Color, i, p_array[i]);
+#else
+ real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 4, i);
+ const Color &elem = p_array[i];
+ raw[0] = elem.r;
+ raw[1] = elem.g;
+ raw[2] = elem.b;
+ raw[3] = elem.a;
+#endif
+ }
+
+ return ret;
+}
+
+PoolColorArray mono_array_to_PoolColorArray(MonoArray *p_array) {
+ PoolColorArray ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 4, i);
+ MARSHALLED_IN(Color, raw_elem, elem);
+ ret.push_back(elem);
+ }
+
+ return ret;
+}
+
+MonoArray *PoolVector2Array_to_mono_array(const PoolVector2Array &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+#ifdef YOLOCOPY
+ mono_array_set(ret, Vector2, i, p_array[i]);
+#else
+ real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 2, i);
+ const Vector2 &elem = p_array[i];
+ raw[0] = elem.x;
+ raw[1] = elem.y;
+#endif
+ }
+
+ return ret;
+}
+
+PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array) {
+ PoolVector2Array ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 2, i);
+ MARSHALLED_IN(Vector2, raw_elem, elem);
+ ret.push_back(elem);
+ }
+
+ return ret;
+}
+
+MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array) {
+ MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), p_array.size());
+
+ for (int i = 0; i < p_array.size(); i++) {
+#ifdef YOLOCOPY
+ mono_array_set(ret, Vector3, i, p_array[i]);
+#else
+ real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 3, i);
+ const Vector3 &elem = p_array[i];
+ raw[0] = elem.x;
+ raw[1] = elem.y;
+ raw[2] = elem.z;
+#endif
+ }
+
+ return ret;
+}
+
+PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
+ PoolVector3Array ret;
+ int length = mono_array_length(p_array);
+
+ for (int i = 0; i < length; i++) {
+ real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 3, i);
+ MARSHALLED_IN(Vector3, raw_elem, elem);
+ ret.push_back(elem);
+ }
+
+ return ret;
+}
+
+MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict) {
+ MonoArray *keys = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
+ MonoArray *values = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size());
+
+ int i = 0;
+ const Variant *dkey = NULL;
+ while ((dkey = p_dict.next(dkey))) {
+ mono_array_set(keys, MonoObject *, i, variant_to_mono_object(dkey));
+ mono_array_set(values, MonoObject *, i, variant_to_mono_object(p_dict[*dkey]));
+ i++;
+ }
+
+ GDMonoUtils::MarshalUtils_ArraysToDict arrays_to_dict = CACHED_METHOD_THUNK(MarshalUtils, ArraysToDictionary);
+
+ MonoObject *ex = NULL;
+ MonoObject *ret = arrays_to_dict(keys, values, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL_V(NULL);
+ }
+
+ return ret;
+}
+
+Dictionary mono_object_to_Dictionary(MonoObject *p_dict) {
+ Dictionary ret;
+
+ GDMonoUtils::MarshalUtils_DictToArrays dict_to_arrays = CACHED_METHOD_THUNK(MarshalUtils, DictionaryToArrays);
+
+ MonoArray *keys = NULL;
+ MonoArray *values = NULL;
+ MonoObject *ex = NULL;
+ dict_to_arrays(p_dict, &keys, &values, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL_V(Dictionary());
+ }
+
+ int length = mono_array_length(keys);
+
+ for (int i = 0; i < length; i++) {
+ MonoObject *key_obj = mono_array_get(keys, MonoObject *, i);
+ MonoObject *value_obj = mono_array_get(values, MonoObject *, i);
+
+ Variant key = key_obj ? mono_object_to_variant(key_obj) : Variant();
+ Variant value = value_obj ? mono_object_to_variant(value_obj) : Variant();
+
+ ret[key] = value;
+ }
+
+ return ret;
+}
+}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
new file mode 100644
index 0000000000..9f403b787f
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -0,0 +1,219 @@
+/*************************************************************************/
+/* gd_mono_marshal.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef GDMONOMARSHAL_H
+#define GDMONOMARSHAL_H
+
+#include "gd_mono.h"
+#include "gd_mono_utils.h"
+#include "variant.h"
+
+namespace GDMonoMarshal {
+
+template <typename T>
+T unbox(MonoObject *p_obj) {
+ return *(T *)mono_object_unbox(p_obj);
+}
+
+#define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x)
+#define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x)
+#define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x)
+#define BOX_INT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int32_t), &x)
+#define BOX_INT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int16_t), &x)
+#define BOX_INT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int8_t), &x)
+#define BOX_UINT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint64_t), &x)
+#define BOX_UINT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint32_t), &x)
+#define BOX_UINT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint16_t), &x)
+#define BOX_UINT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), &x)
+#define BOX_BOOLEAN(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(bool), &x)
+#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
+#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
+
+Variant::Type managed_to_variant_type(const ManagedType &p_type);
+
+// String
+
+String mono_to_utf8_string(MonoString *p_mono_string);
+String mono_to_utf16_string(MonoString *p_mono_string);
+
+_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
+ if (sizeof(CharType) == 2)
+ return mono_to_utf16_string(p_mono_string);
+
+ return mono_to_utf8_string(p_mono_string);
+}
+
+_FORCE_INLINE_ MonoString *mono_from_utf8_string(const String &p_string) {
+ return mono_string_new(mono_domain_get(), p_string.utf8().get_data());
+}
+
+_FORCE_INLINE_ MonoString *mono_from_utf16_string(const String &p_string) {
+ return mono_string_from_utf16((mono_unichar2 *)p_string.c_str());
+}
+
+_FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
+ if (sizeof(CharType) == 2)
+ return mono_from_utf16_string(p_string);
+
+ return mono_from_utf8_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);
+
+_FORCE_INLINE_ MonoObject *variant_to_mono_object(Variant p_var) {
+ return variant_to_mono_object(&p_var);
+}
+
+Variant mono_object_to_variant(MonoObject *p_obj);
+Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type);
+
+// Array
+
+MonoArray *Array_to_mono_array(const Array &p_array);
+Array mono_array_to_Array(MonoArray *p_array);
+
+// PoolIntArray
+
+MonoArray *PoolIntArray_to_mono_array(const PoolIntArray &p_array);
+PoolIntArray mono_array_to_PoolIntArray(MonoArray *p_array);
+
+// PoolByteArray
+
+MonoArray *PoolByteArray_to_mono_array(const PoolByteArray &p_array);
+PoolByteArray mono_array_to_PoolByteArray(MonoArray *p_array);
+
+// PoolRealArray
+
+MonoArray *PoolRealArray_to_mono_array(const PoolRealArray &p_array);
+PoolRealArray mono_array_to_PoolRealArray(MonoArray *p_array);
+
+// PoolStringArray
+
+MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array);
+PoolStringArray mono_array_to_PoolStringArray(MonoArray *p_array);
+
+// PoolColorArray
+
+MonoArray *PoolColorArray_to_mono_array(const PoolColorArray &p_array);
+PoolColorArray mono_array_to_PoolColorArray(MonoArray *p_array);
+
+// PoolVector2Array
+
+MonoArray *PoolVector2Array_to_mono_array(const PoolVector2Array &p_array);
+PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
+
+// PoolVector3Array
+
+MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
+PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
+
+// Dictionary
+
+MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict);
+Dictionary mono_object_to_Dictionary(MonoObject *p_dict);
+
+#ifdef YOLO_COPY
+#define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
+#define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
+#else
+
+// Expects m_in to be of type float*
+
+#define MARSHALLED_OUT(m_t, m_in, m_out) MARSHALLED_OUT_##m_t(m_in, m_out)
+#define MARSHALLED_IN(m_t, m_in, m_out) MARSHALLED_IN_##m_t(m_in, m_out)
+
+// Vector2
+
+#define MARSHALLED_OUT_Vector2(m_in, m_out) real_t m_out[2] = { m_in.x, m_in.y };
+#define MARSHALLED_IN_Vector2(m_in, m_out) Vector2 m_out(m_in[0], m_in[1]);
+
+// Rect2
+
+#define MARSHALLED_OUT_Rect2(m_in, m_out) real_t m_out[4] = { m_in.position.x, m_in.position.y, m_in.size.width, m_in.size.height };
+#define MARSHALLED_IN_Rect2(m_in, m_out) Rect2 m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+
+// Transform2D
+
+#define MARSHALLED_OUT_Transform2D(m_in, m_out) real_t m_out[6] = { m_in[0].x, m_in[0].y, m_in[1].x, m_in[1].y, m_in[2].x, m_in[2].y };
+#define MARSHALLED_IN_Transform2D(m_in, m_out) Transform2D m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5]);
+
+// Vector3
+
+#define MARSHALLED_OUT_Vector3(m_in, m_out) real_t m_out[3] = { m_in.x, m_in.y, m_in.z };
+#define MARSHALLED_IN_Vector3(m_in, m_out) Vector3 m_out(m_in[0], m_in[1], m_in[2]);
+
+// Basis
+
+#define MARSHALLED_OUT_Basis(m_in, m_out) real_t m_out[9] = { \
+ m_in[0].x, m_in[0].y, m_in[0].z, \
+ m_in[1].x, m_in[1].y, m_in[1].z, \
+ m_in[2].x, m_in[2].y, m_in[2].z \
+};
+#define MARSHALLED_IN_Basis(m_in, m_out) Basis m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]);
+
+// Quat
+
+#define MARSHALLED_OUT_Quat(m_in, m_out) real_t m_out[4] = { m_in.x, m_in.y, m_in.z, m_in.w };
+#define MARSHALLED_IN_Quat(m_in, m_out) Quat m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+
+// Transform
+
+#define MARSHALLED_OUT_Transform(m_in, m_out) real_t m_out[12] = { \
+ m_in.basis[0].x, m_in.basis[0].y, m_in.basis[0].z, \
+ m_in.basis[1].x, m_in.basis[1].y, m_in.basis[1].z, \
+ m_in.basis[2].x, m_in.basis[2].y, m_in.basis[2].z, \
+ m_in.origin.x, m_in.origin.y, m_in.origin.z \
+};
+#define MARSHALLED_IN_Transform(m_in, m_out) Transform m_out( \
+ Basis(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]), \
+ Vector3(m_in[9], m_in[10], m_in[11]));
+
+// Rect3
+
+#define MARSHALLED_OUT_Rect3(m_in, m_out) real_t m_out[6] = { m_in.position.x, m_in.position.y, m_in.position.z, m_in.size.x, m_in.size.y, m_in.size.z };
+#define MARSHALLED_IN_Rect3(m_in, m_out) Rect3 m_out(Vector3(m_in[0], m_in[1], m_in[2]), Vector3(m_in[3], m_in[4], m_in[5]));
+
+// Color
+
+#define MARSHALLED_OUT_Color(m_in, m_out) real_t m_out[4] = { m_in.r, m_in.g, m_in.b, m_in.a };
+#define MARSHALLED_IN_Color(m_in, m_out) Color m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+
+// Plane
+
+#define MARSHALLED_OUT_Plane(m_in, m_out) real_t m_out[4] = { m_in.normal.x, m_in.normal.y, m_in.normal.z, m_in.d };
+#define MARSHALLED_IN_Plane(m_in, m_out) Plane m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+
+#endif
+
+} // GDMonoMarshal
+
+#endif // GDMONOMARSHAL_H
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
new file mode 100644
index 0000000000..eb97d62900
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -0,0 +1,227 @@
+/*************************************************************************/
+/* gd_mono_method.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_method.h"
+
+#include "gd_mono_class.h"
+#include "gd_mono_marshal.h"
+
+void GDMonoMethod::_update_signature() {
+ // Apparently MonoMethodSignature needs not to be freed.
+ // mono_method_signature caches the result, we don't need to cache it ourselves.
+
+ MonoMethodSignature *method_sig = mono_method_signature(mono_method);
+ _update_signature(method_sig);
+}
+
+void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
+ is_instance = mono_signature_is_instance(p_method_sig);
+ params_count = mono_signature_get_param_count(p_method_sig);
+
+ MonoType *ret_type = mono_signature_get_return_type(p_method_sig);
+ if (ret_type) {
+ return_type.type_encoding = mono_type_get_type(ret_type);
+
+ if (return_type.type_encoding != MONO_TYPE_VOID) {
+ MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
+ return_type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
+ }
+ }
+
+ void *iter = NULL;
+ MonoType *param_raw_type;
+ while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != NULL) {
+ ManagedType param_type;
+
+ param_type.type_encoding = mono_type_get_type(param_raw_type);
+
+ if (param_type.type_encoding != MONO_TYPE_VOID) {
+ MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
+ param_type.type_class = GDMono::get_singleton()->get_class(param_type_class);
+ }
+
+ param_types.push_back(param_type);
+ }
+}
+
+void *GDMonoMethod::get_thunk() {
+ return mono_method_get_unmanaged_thunk(mono_method);
+}
+
+MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoObject **r_exc) {
+ if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) {
+ MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count());
+
+ for (int i = 0; i < params_count; i++) {
+ MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]);
+ mono_array_set(params, MonoObject *, i, boxed_param);
+ }
+
+ MonoObject *exc = NULL;
+ MonoObject *ret = mono_runtime_invoke_array(mono_method, p_object, params, &exc);
+
+ if (exc) {
+ if (r_exc) {
+ *r_exc = exc;
+ } else {
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ }
+ }
+
+ return ret;
+ } else {
+ MonoObject *exc = NULL;
+ mono_runtime_invoke(mono_method, p_object, NULL, &exc);
+
+ if (exc) {
+ if (r_exc) {
+ *r_exc = exc;
+ } else {
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ }
+ }
+
+ return NULL;
+ }
+}
+
+MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoObject **r_exc) {
+ ERR_FAIL_COND_V(get_parameters_count() > 0, NULL);
+ return invoke_raw(p_object, NULL, r_exc);
+}
+
+MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc) {
+ MonoObject *exc = NULL;
+ MonoObject *ret = mono_runtime_invoke(mono_method, p_object, p_params, &exc);
+
+ if (exc) {
+ if (r_exc) {
+ *r_exc = exc;
+ } else {
+ ERR_PRINT(GDMonoUtils::get_exception_name_and_message(exc).utf8());
+ mono_print_unhandled_exception(exc);
+ }
+ }
+
+ return ret;
+}
+
+bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) {
+ ERR_FAIL_NULL_V(p_attr_class, false);
+
+ if (!attrs_fetched)
+ fetch_attributes();
+
+ if (!attributes)
+ return false;
+
+ return mono_custom_attrs_has_attr(attributes, p_attr_class->get_raw());
+}
+
+MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) {
+ ERR_FAIL_NULL_V(p_attr_class, NULL);
+
+ if (!attrs_fetched)
+ fetch_attributes();
+
+ if (!attributes)
+ return NULL;
+
+ return mono_custom_attrs_get_attr(attributes, p_attr_class->get_raw());
+}
+
+void GDMonoMethod::fetch_attributes() {
+ ERR_FAIL_COND(attributes != NULL);
+ attributes = mono_custom_attrs_from_method(mono_method);
+ attrs_fetched = true;
+}
+
+String GDMonoMethod::get_full_name(bool p_signature) const {
+ char *res = mono_method_full_name(mono_method, p_signature);
+ String full_name(res);
+ mono_free(res);
+ return full_name;
+}
+
+String GDMonoMethod::get_full_name_no_class() const {
+ String res;
+
+ MonoMethodSignature *method_sig = mono_method_signature(mono_method);
+
+ char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
+ res += ret_str;
+ mono_free(ret_str);
+
+ res += " ";
+ res += name;
+ res += "(";
+
+ char *sig_desc = mono_signature_get_desc(method_sig, true);
+ res += sig_desc;
+ mono_free(sig_desc);
+
+ res += ")";
+
+ return res;
+}
+
+String GDMonoMethod::get_ret_type_full_name() const {
+ MonoMethodSignature *method_sig = mono_method_signature(mono_method);
+ char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
+ String res = ret_str;
+ mono_free(ret_str);
+ return res;
+}
+
+String GDMonoMethod::get_signature_desc(bool p_namespaces) const {
+ MonoMethodSignature *method_sig = mono_method_signature(mono_method);
+ char *sig_desc = mono_signature_get_desc(method_sig, p_namespaces);
+ String res = sig_desc;
+ mono_free(sig_desc);
+ return res;
+}
+
+GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) {
+ name = p_name;
+
+ mono_method = p_method;
+
+ attrs_fetched = false;
+ attributes = NULL;
+
+ _update_signature();
+}
+
+GDMonoMethod::~GDMonoMethod() {
+ if (attributes) {
+ mono_custom_attrs_free(attributes);
+ }
+}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
new file mode 100644
index 0000000000..ea4bc8e707
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -0,0 +1,81 @@
+/*************************************************************************/
+/* gd_mono_method.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_METHOD_H
+#define GD_MONO_METHOD_H
+
+#include "gd_mono.h"
+#include "gd_mono_header.h"
+
+class GDMonoMethod {
+
+ StringName name;
+
+ bool is_instance;
+ int params_count;
+ ManagedType return_type;
+ Vector<ManagedType> param_types;
+
+ bool attrs_fetched;
+ MonoCustomAttrInfo *attributes;
+
+ void _update_signature();
+ void _update_signature(MonoMethodSignature *p_method_sig);
+
+ friend class GDMonoClass;
+
+ MonoMethod *mono_method;
+
+public:
+ _FORCE_INLINE_ StringName get_name() { return name; }
+
+ _FORCE_INLINE_ bool is_static() { return !is_instance; }
+ _FORCE_INLINE_ int get_parameters_count() { return params_count; }
+ _FORCE_INLINE_ ManagedType get_return_type() { return return_type; }
+
+ void *get_thunk();
+
+ MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoObject **r_exc = NULL);
+ MonoObject *invoke(MonoObject *p_object, MonoObject **r_exc = NULL);
+ MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoObject **r_exc = NULL);
+
+ bool has_attribute(GDMonoClass *p_attr_class);
+ MonoObject *get_attribute(GDMonoClass *p_attr_class);
+ void fetch_attributes();
+
+ String get_full_name(bool p_signature = false) const;
+ String get_full_name_no_class() const;
+ String get_ret_type_full_name() const;
+ String get_signature_desc(bool p_namespaces = false) const;
+
+ GDMonoMethod(StringName p_name, MonoMethod *p_method);
+ ~GDMonoMethod();
+};
+
+#endif // GD_MONO_METHOD_H
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
new file mode 100644
index 0000000000..53e45002c4
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -0,0 +1,367 @@
+/*************************************************************************/
+/* gd_mono_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_utils.h"
+
+#include "os/dir_access.h"
+#include "project_settings.h"
+#include "reference.h"
+
+#include "../csharp_script.h"
+#include "gd_mono.h"
+#include "gd_mono_class.h"
+#include "gd_mono_marshal.h"
+
+namespace GDMonoUtils {
+
+MonoCache mono_cache;
+
+#define CACHE_AND_CHECK(m_var, m_val) \
+ { \
+ m_var = m_val; \
+ if (!m_var) ERR_PRINT("Mono Cache: Member " #m_var " is null. This is really bad!"); \
+ }
+
+#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_class, m_val)
+#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_ns##_##m_class, m_val)
+#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.rawclass_##m_class, m_val)
+#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val)
+#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
+
+void MonoCache::clear_members() {
+
+ class_MonoObject = NULL;
+ class_bool = NULL;
+ class_int8_t = NULL;
+ class_int16_t = NULL;
+ class_int32_t = NULL;
+ class_int64_t = NULL;
+ class_uint8_t = NULL;
+ class_uint16_t = NULL;
+ class_uint32_t = NULL;
+ class_uint64_t = NULL;
+ class_float = NULL;
+ class_double = NULL;
+ class_String = NULL;
+ class_IntPtr = NULL;
+
+ rawclass_Dictionary = NULL;
+
+ class_Vector2 = NULL;
+ class_Rect2 = NULL;
+ class_Transform2D = NULL;
+ class_Vector3 = NULL;
+ class_Basis = NULL;
+ class_Quat = NULL;
+ class_Transform = NULL;
+ class_Rect3 = NULL;
+ class_Color = NULL;
+ class_Plane = NULL;
+ class_NodePath = NULL;
+ class_RID = NULL;
+ class_GodotObject = NULL;
+ class_GodotReference = NULL;
+ class_Node = NULL;
+ class_Control = NULL;
+ class_Spatial = NULL;
+ class_WeakRef = NULL;
+ class_MarshalUtils = NULL;
+
+ class_ExportAttribute = NULL;
+ field_ExportAttribute_hint = NULL;
+ field_ExportAttribute_hint_string = NULL;
+ class_ToolAttribute = NULL;
+ class_RemoteAttribute = NULL;
+ class_SyncAttribute = NULL;
+ class_MasterAttribute = NULL;
+ class_SlaveAttribute = NULL;
+ class_GodotMethodAttribute = NULL;
+ field_GodotMethodAttribute_methodName = NULL;
+
+ field_GodotObject_ptr = NULL;
+ field_NodePath_ptr = NULL;
+ field_Image_ptr = NULL;
+ field_RID_ptr = NULL;
+
+ methodthunk_MarshalUtils_DictionaryToArrays = NULL;
+ methodthunk_MarshalUtils_ArraysToDictionary = NULL;
+ methodthunk_SignalAwaiter_SignalCallback = NULL;
+ methodthunk_SignalAwaiter_FailureCallback = NULL;
+ methodthunk_GodotTaskScheduler_Activate = NULL;
+
+ task_scheduler_handle = Ref<MonoGCHandle>();
+}
+
+#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
+
+void update_corlib_cache() {
+
+ CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
+ CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class()));
+ CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class()));
+ CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class()));
+ CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class()));
+ CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class()));
+ CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class()));
+ CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class()));
+ CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class()));
+ CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class()));
+ CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class()));
+ CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class()));
+ CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
+ CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
+}
+
+void update_godot_api_cache() {
+
+ CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
+ CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
+ CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
+ CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
+ CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
+ CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat));
+ CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform));
+ CACHE_CLASS_AND_CHECK(Rect3, GODOT_API_CLASS(Rect3));
+ CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
+ CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
+ CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
+ CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(NodePath));
+ CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
+ CACHE_CLASS_AND_CHECK(GodotReference, GODOT_API_CLASS(Reference));
+ CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
+ CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
+ CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial));
+ CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
+ CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
+
+ // Attributes
+ CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
+ CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
+ CACHE_FIELD_AND_CHECK(ExportAttribute, hint_string, CACHED_CLASS(ExportAttribute)->get_field("hint_string"));
+ CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
+ CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
+ CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute));
+ CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute));
+ CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute));
+ CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
+ CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
+
+ CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
+ CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
+ CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
+
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryToArrays, (MarshalUtils_DictToArrays)CACHED_CLASS(MarshalUtils)->get_method("DictionaryToArrays", 3)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArraysToDictionary, (MarshalUtils_ArraysToDict)CACHED_CLASS(MarshalUtils)->get_method("ArraysToDictionary", 2)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk());
+ CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk());
+
+ {
+ /*
+ * TODO Right now we only support Dictionary<object, object>.
+ * It would be great if we could support other key/value types
+ * without forcing the user to copy the entries.
+ */
+ GDMonoMethod *method_get_dict_type = CACHED_CLASS(MarshalUtils)->get_method("GetDictionaryType", 0);
+ ERR_FAIL_NULL(method_get_dict_type);
+ MonoReflectionType *dict_refl_type = (MonoReflectionType *)method_get_dict_type->invoke(NULL);
+ ERR_FAIL_NULL(dict_refl_type);
+ MonoType *dict_type = mono_reflection_type_get_type(dict_refl_type);
+ ERR_FAIL_NULL(dict_type);
+
+ CACHE_RAW_MONO_CLASS_AND_CHECK(Dictionary, mono_class_from_mono_type(dict_type));
+ }
+
+ MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_raw());
+ mono_runtime_object_init(task_scheduler);
+ mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler);
+}
+
+void clear_cache() {
+ mono_cache.cleanup();
+ mono_cache.clear_members();
+}
+
+MonoObject *unmanaged_get_managed(Object *unmanaged) {
+ if (unmanaged) {
+ if (unmanaged->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance());
+
+ if (cs_instance) {
+ return cs_instance->get_mono_object();
+ }
+ }
+
+ // Only called if the owner does not have a CSharpInstance
+ void *data = unmanaged->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
+
+ if (data) {
+ return ((Map<Object *, Ref<MonoGCHandle> >::Element *)data)->value()->get_target();
+ }
+ }
+
+ return NULL;
+}
+
+void set_main_thread(MonoThread *p_thread) {
+ mono_thread_set_main(p_thread);
+}
+
+void attach_current_thread() {
+ ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
+ MonoThread *mono_thread = mono_thread_attach(SCRIPTS_DOMAIN);
+ ERR_FAIL_NULL(mono_thread);
+}
+
+void detach_current_thread() {
+ ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
+ MonoThread *mono_thread = mono_thread_current();
+ ERR_FAIL_NULL(mono_thread);
+ mono_thread_detach(mono_thread);
+}
+
+MonoThread *get_current_thread() {
+ return mono_thread_current();
+}
+
+GDMonoClass *get_object_class(MonoObject *p_object) {
+ return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
+}
+
+GDMonoClass *type_get_proxy_class(const StringName &p_type) {
+ String class_name = p_type;
+
+ if (class_name[0] == '_')
+ class_name = class_name.substr(1, class_name.length());
+
+ GDMonoClass *klass = GDMono::get_singleton()->get_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
+
+#ifdef TOOLS_ENABLED
+ if (!klass) {
+ return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
+ }
+#endif
+
+ return klass;
+}
+
+GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
+ GDMonoClass *klass = p_class;
+
+ do {
+ const GDMonoAssembly *assembly = klass->get_assembly();
+ if (assembly == GDMono::get_singleton()->get_api_assembly())
+ return klass;
+#ifdef TOOLS_ENABLED
+ if (assembly == GDMono::get_singleton()->get_editor_api_assembly())
+ return klass;
+#endif
+ } while ((klass = klass->get_parent_class()) != NULL);
+
+ return NULL;
+}
+
+MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
+ String object_type = p_object->get_class_name();
+
+ if (object_type[0] == '_')
+ object_type = object_type.substr(1, object_type.length());
+
+ if (!ClassDB::is_parent_class(object_type, p_native)) {
+ ERR_EXPLAIN("Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'");
+ ERR_FAIL_V(NULL);
+ }
+
+ MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_raw());
+ ERR_FAIL_NULL_V(mono_object, NULL);
+
+ CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
+
+ // Construct
+ mono_runtime_object_init(mono_object);
+
+ return mono_object;
+}
+
+MonoObject *create_managed_from(const NodePath &p_from) {
+ MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(NodePath));
+ ERR_FAIL_NULL_V(mono_object, NULL);
+
+ // Construct
+ mono_runtime_object_init(mono_object);
+
+ CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
+
+ return mono_object;
+}
+
+MonoObject *create_managed_from(const RID &p_from) {
+ MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(RID));
+ ERR_FAIL_NULL_V(mono_object, NULL);
+
+ // Construct
+ mono_runtime_object_init(mono_object);
+
+ CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
+
+ return mono_object;
+}
+
+MonoDomain *create_domain(const String &p_friendly_name) {
+ MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
+
+ if (domain) {
+ // Workaround to avoid this exception:
+ // System.Configuration.ConfigurationErrorsException: Error Initializing the configuration system.
+ // ---> System.ArgumentException: The 'ExeConfigFilename' argument cannot be null.
+ mono_domain_set_config(domain, ".", "");
+ }
+
+ return domain;
+}
+
+String get_exception_name_and_message(MonoObject *p_ex) {
+ String res;
+
+ MonoClass *klass = mono_object_get_class(p_ex);
+ MonoType *type = mono_class_get_type(klass);
+
+ char *full_name = mono_type_full_name(type);
+ res += full_name;
+ mono_free(full_name);
+
+ res += ": ";
+
+ MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
+ MonoString *msg = (MonoString *)mono_property_get_value(prop, p_ex, NULL, NULL);
+ res += GDMonoMarshal::mono_string_to_godot(msg);
+
+ return res;
+}
+}
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
new file mode 100644
index 0000000000..ebb5d28e4d
--- /dev/null
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -0,0 +1,186 @@
+/*************************************************************************/
+/* gd_mono_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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_MONOUTILS_H
+#define GD_MONOUTILS_H
+
+#include <mono/metadata/threads.h>
+
+#include "../mono_gc_handle.h"
+#include "gd_mono_header.h"
+
+#include "object.h"
+#include "reference.h"
+
+namespace GDMonoUtils {
+
+typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **);
+typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **);
+typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray **, MonoObject **);
+typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **);
+typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **);
+
+struct MonoCache {
+ // Format for cached classes in the Godot namespace: class_<Class>
+ // Macro: CACHED_CLASS(<Class>)
+
+ // Format for cached classes in a different namespace: class_<Namespace>_<Class>
+ // Macro: CACHED_NS_CLASS(<Namespace>, <Class>)
+
+ // -----------------------------------------------
+ // corlib classes
+
+ // Let's use the no-namespace format for these too
+ GDMonoClass *class_MonoObject;
+ GDMonoClass *class_bool;
+ GDMonoClass *class_int8_t;
+ GDMonoClass *class_int16_t;
+ GDMonoClass *class_int32_t;
+ GDMonoClass *class_int64_t;
+ GDMonoClass *class_uint8_t;
+ GDMonoClass *class_uint16_t;
+ GDMonoClass *class_uint32_t;
+ GDMonoClass *class_uint64_t;
+ GDMonoClass *class_float;
+ GDMonoClass *class_double;
+ GDMonoClass *class_String;
+ GDMonoClass *class_IntPtr;
+
+ MonoClass *rawclass_Dictionary;
+ // -----------------------------------------------
+
+ GDMonoClass *class_Vector2;
+ GDMonoClass *class_Rect2;
+ GDMonoClass *class_Transform2D;
+ GDMonoClass *class_Vector3;
+ GDMonoClass *class_Basis;
+ GDMonoClass *class_Quat;
+ GDMonoClass *class_Transform;
+ GDMonoClass *class_Rect3;
+ GDMonoClass *class_Color;
+ GDMonoClass *class_Plane;
+ GDMonoClass *class_NodePath;
+ GDMonoClass *class_RID;
+ GDMonoClass *class_GodotObject;
+ GDMonoClass *class_GodotReference;
+ GDMonoClass *class_Node;
+ GDMonoClass *class_Control;
+ GDMonoClass *class_Spatial;
+ GDMonoClass *class_WeakRef;
+ GDMonoClass *class_MarshalUtils;
+
+ GDMonoClass *class_ExportAttribute;
+ GDMonoField *field_ExportAttribute_hint;
+ GDMonoField *field_ExportAttribute_hint_string;
+ GDMonoClass *class_ToolAttribute;
+ GDMonoClass *class_RemoteAttribute;
+ GDMonoClass *class_SyncAttribute;
+ GDMonoClass *class_MasterAttribute;
+ GDMonoClass *class_SlaveAttribute;
+ GDMonoClass *class_GodotMethodAttribute;
+ GDMonoField *field_GodotMethodAttribute_methodName;
+
+ GDMonoField *field_GodotObject_ptr;
+ GDMonoField *field_NodePath_ptr;
+ GDMonoField *field_Image_ptr;
+ GDMonoField *field_RID_ptr;
+
+ MarshalUtils_DictToArrays methodthunk_MarshalUtils_DictionaryToArrays;
+ MarshalUtils_ArraysToDict methodthunk_MarshalUtils_ArraysToDictionary;
+ SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback;
+ SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback;
+ GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate;
+
+ Ref<MonoGCHandle> task_scheduler_handle;
+
+ void clear_members();
+ void cleanup() {}
+
+ MonoCache() {
+ clear_members();
+ }
+};
+
+extern MonoCache mono_cache;
+
+void update_corlib_cache();
+void update_godot_api_cache();
+void clear_cache();
+
+_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
+ p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
+}
+
+/**
+ * If the object has a csharp script, returns the target of the gchandle stored in the script instance
+ * Otherwise returns a newly constructed MonoObject* which is attached to the object
+ * Returns NULL on error
+ */
+MonoObject *unmanaged_get_managed(Object *unmanaged);
+
+void set_main_thread(MonoThread *p_thread);
+void attach_current_thread();
+void detach_current_thread();
+MonoThread *get_current_thread();
+
+_FORCE_INLINE_ bool is_main_thread() {
+ return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current();
+}
+
+GDMonoClass *get_object_class(MonoObject *p_object);
+GDMonoClass *type_get_proxy_class(const StringName &p_type);
+GDMonoClass *get_class_native_base(GDMonoClass *p_class);
+
+MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object);
+
+MonoObject *create_managed_from(const NodePath &p_from);
+MonoObject *create_managed_from(const RID &p_from);
+
+MonoDomain *create_domain(const String &p_friendly_name);
+
+String get_exception_name_and_message(MonoObject *p_ex);
+
+} // GDMonoUtils
+
+#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL)))
+
+#define CACHED_CLASS(m_class) (GDMonoUtils::mono_cache.class_##m_class)
+#define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_raw())
+#define CACHED_NS_CLASS(m_ns, m_class) (GDMonoUtils::mono_cache.class_##m_ns##_##m_class)
+#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoUtils::mono_cache.rawclass_##m_class)
+#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field)
+#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method)
+
+#ifdef REAL_T_IS_DOUBLE
+#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double)
+#else
+#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float)
+#endif
+
+#endif // GD_MONOUTILS_H
diff --git a/modules/mono/mono_reg_utils.py b/modules/mono/mono_reg_utils.py
new file mode 100644
index 0000000000..8ddddb3a24
--- /dev/null
+++ b/modules/mono/mono_reg_utils.py
@@ -0,0 +1,114 @@
+import os
+import platform
+
+from compat import decode_utf8
+
+if os.name == 'nt':
+ import sys
+ if sys.version_info < (3,):
+ import _winreg as winreg
+ else:
+ import winreg
+
+
+def _reg_open_key(key, subkey):
+ try:
+ return winreg.OpenKey(key, subkey)
+ except (WindowsError, OSError):
+ if platform.architecture()[0] == '32bit':
+ bitness_sam = winreg.KEY_WOW64_64KEY
+ else:
+ bitness_sam = winreg.KEY_WOW64_32KEY
+ return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam)
+
+
+def _reg_open_key_bits(key, subkey, bits):
+ sam = winreg.KEY_READ
+
+ if platform.architecture()[0] == '32bit':
+ if bits == '64':
+ # Force 32bit process to search in 64bit registry
+ sam |= winreg.KEY_WOW64_64KEY
+ else:
+ if bits == '32':
+ # Force 64bit process to search in 32bit registry
+ sam |= winreg.KEY_WOW64_32KEY
+
+ return winreg.OpenKey(key, subkey, 0, sam)
+
+
+def _find_mono_in_reg(subkey, bits):
+ try:
+ with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
+ value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
+ return value
+ except (WindowsError, OSError):
+ return None
+
+
+def _find_mono_in_reg_old(subkey, bits):
+ try:
+ with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
+ default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
+ if default_clr:
+ return _find_mono_in_reg(subkey + '\\' + default_clr, bits)
+ return None
+ except (WindowsError, EnvironmentError):
+ return None
+
+
+def find_mono_root_dir(bits):
+ root_dir = _find_mono_in_reg(r'SOFTWARE\Mono', bits)
+ if root_dir is not None:
+ return root_dir
+ root_dir = _find_mono_in_reg_old(r'SOFTWARE\Novell\Mono', bits)
+ if root_dir is not None:
+ return root_dir
+ return ''
+
+
+def find_msbuild_tools_path_reg():
+ import subprocess
+
+ vswhere = os.getenv('PROGRAMFILES(X86)')
+ if not vswhere:
+ vswhere = os.getenv('PROGRAMFILES')
+ vswhere += r'\Microsoft Visual Studio\Installer\vswhere.exe'
+
+ vswhere_args = ['-latest', '-requires', 'Microsoft.Component.MSBuild']
+
+ try:
+ lines = subprocess.check_output([vswhere] + vswhere_args).splitlines()
+
+ for line in lines:
+ parts = decode_utf8(line).split(':', 1)
+
+ if len(parts) < 2 or parts[0] != 'installationPath':
+ continue
+
+ val = parts[1].strip()
+
+ if not val:
+ raise ValueError('Value of `installationPath` entry is empty')
+
+ return os.path.join(val, "MSBuild\\15.0\\Bin")
+
+ raise ValueError('Cannot find `installationPath` entry')
+ except ValueError as e:
+ print('Error reading output from vswhere: ' + e.message)
+ except WindowsError:
+ pass # Fine, vswhere not found
+ except (subprocess.CalledProcessError, OSError):
+ pass
+
+ # Try to find 14.0 in the Registry
+
+ try:
+ subkey = r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0'
+ with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
+ value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
+ return value
+ except (WindowsError, OSError):
+ return ''
+
+ return ''
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
new file mode 100644
index 0000000000..2656de5b14
--- /dev/null
+++ b/modules/mono/register_types.cpp
@@ -0,0 +1,72 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 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 "project_settings.h"
+
+#include "csharp_script.h"
+
+CSharpLanguage *script_language_cs = NULL;
+ResourceFormatLoaderCSharpScript *resource_loader_cs = NULL;
+ResourceFormatSaverCSharpScript *resource_saver_cs = NULL;
+
+_GodotSharp *_godotsharp = NULL;
+
+void register_mono_types() {
+ ClassDB::register_class<CSharpScript>();
+
+ _godotsharp = memnew(_GodotSharp);
+
+ ClassDB::register_class<_GodotSharp>();
+ ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("GodotSharp", _GodotSharp::get_singleton()));
+
+ script_language_cs = memnew(CSharpLanguage);
+ script_language_cs->set_language_index(ScriptServer::get_language_count());
+ ScriptServer::register_language(script_language_cs);
+
+ resource_loader_cs = memnew(ResourceFormatLoaderCSharpScript);
+ ResourceLoader::add_resource_format_loader(resource_loader_cs);
+ resource_saver_cs = memnew(ResourceFormatSaverCSharpScript);
+ ResourceSaver::add_resource_format_saver(resource_saver_cs);
+}
+
+void unregister_mono_types() {
+ ScriptServer::unregister_language(script_language_cs);
+
+ if (script_language_cs)
+ memdelete(script_language_cs);
+ if (resource_loader_cs)
+ memdelete(resource_loader_cs);
+ if (resource_saver_cs)
+ memdelete(resource_saver_cs);
+
+ if (_godotsharp)
+ memdelete(_godotsharp);
+}
diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h
new file mode 100644
index 0000000000..6cf706b944
--- /dev/null
+++ b/modules/mono/register_types.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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_mono_types();
+void unregister_mono_types();
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
new file mode 100644
index 0000000000..7e99df29a1
--- /dev/null
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -0,0 +1,144 @@
+/*************************************************************************/
+/* signal_awaiter_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "signal_awaiter_utils.h"
+
+#include "csharp_script.h"
+#include "mono_gd/gd_mono_class.h"
+#include "mono_gd/gd_mono_marshal.h"
+#include "mono_gd/gd_mono_utils.h"
+
+namespace SignalAwaiterUtils {
+
+Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p_target, MonoObject *p_awaiter) {
+
+ ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA);
+ ERR_FAIL_NULL_V(p_target, ERR_INVALID_DATA);
+
+ uint32_t awaiter_handle = MonoGCHandle::make_strong_handle(p_awaiter);
+ Ref<SignalAwaiterHandle> sa_con = memnew(SignalAwaiterHandle(awaiter_handle));
+#ifdef DEBUG_ENABLED
+ sa_con->set_connection_target(p_target);
+#endif
+
+ Vector<Variant> binds;
+ binds.push_back(sa_con);
+
+ Error err = p_source->connect(p_signal, sa_con.ptr(),
+ CSharpLanguage::get_singleton()->get_string_names()._signal_callback,
+ binds, Object::CONNECT_ONESHOT);
+
+ if (err != OK) {
+ // Set it as completed to prevent it from calling the failure callback when released.
+ // The awaiter will be aware of the failure by checking the returned error.
+ sa_con->set_completed(true);
+ }
+
+ return err;
+}
+}
+
+Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+
+#ifdef DEBUG_ENABLED
+ if (conn_target_id && !ObjectDB::get_instance(conn_target_id)) {
+ ERR_EXPLAIN("Resumed after await, but class instance is gone");
+ ERR_FAIL_V(Variant());
+ }
+#endif
+
+ if (p_argcount < 1) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ return Variant();
+ }
+
+ Ref<SignalAwaiterHandle> self = *p_args[p_argcount - 1];
+
+ if (self.is_null()) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = p_argcount - 1;
+ r_error.expected = Variant::OBJECT;
+ return Variant();
+ }
+
+ set_completed(true);
+
+ int signal_argc = p_argcount - 1;
+ MonoArray *signal_args = mono_array_new(SCRIPTS_DOMAIN, CACHED_CLASS_RAW(MonoObject), signal_argc);
+
+ for (int i = 0; i < signal_argc; i++) {
+ MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]);
+ mono_array_set(signal_args, MonoObject *, i, boxed);
+ }
+
+ GDMonoUtils::SignalAwaiter_SignalCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback);
+
+ MonoObject *ex = NULL;
+ thunk(get_target(), &signal_args, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL_V(Variant());
+ }
+
+ return Variant();
+}
+
+void SignalAwaiterHandle::_bind_methods() {
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &SignalAwaiterHandle::_signal_callback, MethodInfo("_signal_callback"));
+}
+
+SignalAwaiterHandle::SignalAwaiterHandle(uint32_t p_managed_handle)
+ : MonoGCHandle(p_managed_handle) {
+
+#ifdef DEBUG_ENABLED
+ conn_target_id = 0;
+#endif
+}
+
+SignalAwaiterHandle::~SignalAwaiterHandle() {
+
+ if (!completed) {
+ GDMonoUtils::SignalAwaiter_FailureCallback thunk = CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback);
+
+ MonoObject *awaiter = get_target();
+
+ if (awaiter) {
+ MonoObject *ex = NULL;
+ thunk(awaiter, &ex);
+
+ if (ex) {
+ mono_print_unhandled_exception(ex);
+ ERR_FAIL_V();
+ }
+ }
+ }
+}
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
new file mode 100644
index 0000000000..0d615b5826
--- /dev/null
+++ b/modules/mono/signal_awaiter_utils.h
@@ -0,0 +1,70 @@
+/*************************************************************************/
+/* signal_awaiter_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef SIGNAL_AWAITER_UTILS_H
+#define SIGNAL_AWAITER_UTILS_H
+
+#include "mono_gc_handle.h"
+#include "reference.h"
+
+namespace SignalAwaiterUtils {
+
+Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p_target, MonoObject *p_awaiter);
+}
+
+class SignalAwaiterHandle : public MonoGCHandle {
+
+ GDCLASS(SignalAwaiterHandle, MonoGCHandle)
+
+ bool completed;
+
+#ifdef DEBUG_ENABLED
+ ObjectID conn_target_id;
+#endif
+
+ Variant _signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+
+protected:
+ static void _bind_methods();
+
+public:
+ _FORCE_INLINE_ bool is_completed() { return completed; }
+ _FORCE_INLINE_ void set_completed(bool p_completed) { completed = p_completed; }
+
+#ifdef DEBUG_ENABLED
+ _FORCE_INLINE_ void set_connection_target(Object *p_target) {
+ conn_target_id = p_target->get_instance_id();
+ }
+#endif
+
+ SignalAwaiterHandle(uint32_t p_managed_handle);
+ ~SignalAwaiterHandle();
+};
+
+#endif // SIGNAL_AWAITER_UTILS_H
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
new file mode 100644
index 0000000000..2e90b3b716
--- /dev/null
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -0,0 +1,228 @@
+/*************************************************************************/
+/* mono_reg_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "mono_reg_utils.h"
+
+#ifdef WINDOWS_ENABLED
+
+#include "os/os.h"
+
+// Here, after os/os.h
+#include <windows.h>
+
+namespace MonoRegUtils {
+
+template <int>
+REGSAM bitness_sam_impl();
+
+template <>
+REGSAM bitness_sam_impl<4>() {
+ return KEY_WOW64_64KEY;
+}
+
+template <>
+REGSAM bitness_sam_impl<8>() {
+ return KEY_WOW64_32KEY;
+}
+
+REGSAM _get_bitness_sam() {
+ return bitness_sam_impl<sizeof(size_t)>();
+}
+
+LONG _RegOpenKey(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult) {
+
+ LONG res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, phkResult);
+
+ if (res != ERROR_SUCCESS)
+ res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ | _get_bitness_sam(), phkResult);
+
+ return res;
+}
+
+LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value) {
+
+ Vector<WCHAR> buffer;
+ buffer.resize(512);
+ DWORD dwBufferSize = buffer.size();
+
+ LONG res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, NULL, (LPBYTE)buffer.ptr(), &dwBufferSize);
+
+ if (res == ERROR_MORE_DATA) {
+ // dwBufferSize now contains the actual size
+ Vector<WCHAR> buffer;
+ buffer.resize(dwBufferSize);
+ res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, NULL, (LPBYTE)buffer.ptr(), &dwBufferSize);
+ }
+
+ if (res == ERROR_SUCCESS) {
+ r_value = String(buffer.ptr(), buffer.size());
+ } else {
+ r_value = String();
+ }
+
+ return res;
+}
+
+LONG _find_mono_in_reg(const String &p_subkey, MonoRegInfo &r_info, bool p_old_reg = false) {
+
+ HKEY hKey;
+ LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, p_subkey.c_str(), &hKey);
+
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+
+ if (!p_old_reg) {
+ res = _RegKeyQueryString(hKey, "Version", r_info.version);
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+ }
+
+ res = _RegKeyQueryString(hKey, "SdkInstallRoot", r_info.install_root_dir);
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+
+ res = _RegKeyQueryString(hKey, "FrameworkAssemblyDirectory", r_info.assembly_dir);
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+
+ res = _RegKeyQueryString(hKey, "MonoConfigDir", r_info.config_dir);
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+
+ if (r_info.install_root_dir.ends_with("\\"))
+ r_info.bin_dir = r_info.install_root_dir + "bin";
+ else
+ r_info.bin_dir = r_info.install_root_dir + "\\bin";
+
+cleanup:
+ RegCloseKey(hKey);
+ return res;
+}
+
+LONG _find_mono_in_reg_old(const String &p_subkey, MonoRegInfo &r_info) {
+
+ String default_clr;
+
+ HKEY hKey;
+ LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, p_subkey.c_str(), &hKey);
+
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+
+ res = _RegKeyQueryString(hKey, "DefaultCLR", default_clr);
+
+ if (res == ERROR_SUCCESS && default_clr.length()) {
+ r_info.version = default_clr;
+ res = _find_mono_in_reg(p_subkey + "\\" + default_clr, r_info, true);
+ }
+
+cleanup:
+ RegCloseKey(hKey);
+ return res;
+}
+
+MonoRegInfo find_mono() {
+
+ MonoRegInfo info;
+
+ if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS)
+ return info;
+
+ if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS)
+ return info;
+
+ ERR_PRINT("Cannot find mono in the registry");
+
+ return MonoRegInfo();
+}
+
+String find_msbuild_tools_path() {
+
+ String msbuild_tools_path;
+
+ // Try to find 15.0 with vswhere
+
+ String vswhere_path = OS::get_singleton()->get_environment(sizeof(size_t) == 8 ? "ProgramFiles(x86)" : "ProgramFiles");
+ vswhere_path += "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
+
+ List<String> vswhere_args;
+ vswhere_args.push_back("-latest");
+ vswhere_args.push_back("-requires");
+ vswhere_args.push_back("Microsoft.Component.MSBuild");
+
+ String output;
+ int exit_code;
+ OS::get_singleton()->execute(vswhere_path, vswhere_args, true, NULL, &output, &exit_code);
+
+ if (exit_code == 0) {
+ Vector<String> lines = output.split("\n");
+
+ for (int i = 0; i < lines.size(); i++) {
+ const String &line = lines[i];
+ int sep_idx = line.find(":");
+
+ if (sep_idx > 0) {
+ String key = line.substr(0, sep_idx); // No need to trim
+
+ if (key == "installationPath") {
+ String val = line.substr(sep_idx + 1, line.length()).strip_edges();
+
+ ERR_BREAK(val.empty());
+
+ if (!val.ends_with("\\")) {
+ val += "\\";
+ }
+
+ return val + "MSBuild\\15.0\\Bin";
+ }
+ }
+ }
+ }
+
+ // Try to find 14.0 in the Registry
+
+ HKEY hKey;
+ LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\14.0", &hKey);
+
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+
+ res = _RegKeyQueryString(hKey, "MSBuildToolsPath", msbuild_tools_path);
+
+ if (res != ERROR_SUCCESS)
+ goto cleanup;
+
+cleanup:
+ RegCloseKey(hKey);
+
+ 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
new file mode 100644
index 0000000000..4cc4965acb
--- /dev/null
+++ b/modules/mono/utils/mono_reg_utils.h
@@ -0,0 +1,54 @@
+/*************************************************************************/
+/* mono_reg_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef MONO_REG_UTILS_H
+#define MONO_REG_UTILS_H
+
+#ifdef WINDOWS_ENABLED
+
+#include "ustring.h"
+
+struct MonoRegInfo {
+
+ String version;
+ String install_root_dir;
+ String assembly_dir;
+ String config_dir;
+ String bin_dir;
+};
+
+namespace MonoRegUtils {
+
+MonoRegInfo find_mono();
+String find_msbuild_tools_path();
+} // MonoRegUtils
+
+#endif // WINDOWS_ENABLED
+
+#endif // MONO_REG_UTILS_H
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
new file mode 100644
index 0000000000..105c2c981e
--- /dev/null
+++ b/modules/mono/utils/path_utils.cpp
@@ -0,0 +1,111 @@
+/*************************************************************************/
+/* path_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "path_utils.h"
+
+#include "os/dir_access.h"
+#include "os/file_access.h"
+#include "os/os.h"
+#include "project_settings.h"
+
+#ifdef WINDOWS_ENABLED
+#define ENV_PATH_SEP ";"
+#else
+#define ENV_PATH_SEP ":"
+#include <limits.h>
+#endif
+
+#include <stdlib.h>
+
+String path_which(const String &p_name) {
+
+#ifdef WINDOWS_ENABLED
+ Vector<String> exts = OS::get_singleton()->get_environment("PATHEXT").split(ENV_PATH_SEP, false);
+#endif
+ Vector<String> env_path = OS::get_singleton()->get_environment("PATH").split(ENV_PATH_SEP, false);
+
+ if (env_path.empty())
+ return String();
+
+ for (int i = 0; i < env_path.size(); i++) {
+ String p = path_join(env_path[i], p_name);
+
+#ifdef WINDOWS_ENABLED
+ for (int j = 0; j < exts.size(); j++) {
+ String p2 = p + exts[j];
+
+ if (FileAccess::exists(p2))
+ return p2;
+ }
+#else
+ if (FileAccess::exists(p))
+ return p;
+#endif
+ }
+
+ return String();
+}
+
+void fix_path(const String &p_path, String &r_out) {
+ r_out = p_path.replace("\\", "/");
+
+ while (true) { // in case of using 2 or more slash
+ String compare = r_out.replace("//", "/");
+ if (r_out == compare)
+ break;
+ else
+ r_out = compare;
+ }
+}
+
+bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
+#ifdef WINDOWS_ENABLED
+ CharType ret[_MAX_PATH];
+ if (_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) {
+ String abspath = String(ret).replace("\\", "/");
+ int pos = abspath.find(":/");
+ if (pos != -1) {
+ r_abs_path = abspath.substr(pos - 1, abspath.length());
+ } else {
+ r_abs_path = abspath;
+ }
+ return true;
+ }
+#else
+ char ret[PATH_MAX];
+ if (realpath(p_existing_path.utf8().get_data(), ret)) {
+ String retstr;
+ if (!retstr.parse_utf8(ret)) {
+ r_abs_path = retstr;
+ return true;
+ }
+ }
+#endif
+ return false;
+}
diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h
new file mode 100644
index 0000000000..445604300d
--- /dev/null
+++ b/modules/mono/utils/path_utils.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* path_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef PATH_UTILS_H
+#define PATH_UTILS_H
+
+#include "ustring.h"
+
+_FORCE_INLINE_ String path_join(const String &e1, const String &e2) {
+ return e1.plus_file(e2);
+}
+
+_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3) {
+ return e1.plus_file(e2).plus_file(e3);
+}
+
+_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3, const String &e4) {
+ return e1.plus_file(e2).plus_file(e3).plus_file(e4);
+}
+
+String path_which(const String &p_name);
+
+void fix_path(const String &p_path, String &r_out);
+
+bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path);
+
+#endif // PATH_UTILS_H
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
new file mode 100644
index 0000000000..f26663ea11
--- /dev/null
+++ b/modules/mono/utils/string_utils.cpp
@@ -0,0 +1,157 @@
+/*************************************************************************/
+/* string_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "string_utils.h"
+
+namespace {
+
+int sfind(const String &p_text, int p_from) {
+ if (p_from < 0)
+ return -1;
+
+ int src_len = 2;
+ int len = p_text.length();
+
+ if (src_len == 0 || len == 0)
+ return -1;
+
+ const CharType *src = p_text.c_str();
+
+ for (int i = p_from; i <= (len - src_len); i++) {
+ bool found = true;
+
+ for (int j = 0; j < src_len; j++) {
+ int read_pos = i + j;
+
+ if (read_pos >= len) {
+ ERR_PRINT("read_pos >= len");
+ return -1;
+ };
+
+ switch (j) {
+ case 0:
+ found = src[read_pos] == '%';
+ break;
+ case 1: {
+ CharType c = src[read_pos];
+ found = src[read_pos] == 's' || (c >= '0' || c <= '4');
+ break;
+ }
+ default:
+ found = false;
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ if (found)
+ return i;
+ }
+
+ return -1;
+}
+}
+
+String sformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
+ if (p_text.length() < 2)
+ return p_text;
+
+ Array args;
+
+ if (p1.get_type() != Variant::NIL) {
+ args.push_back(p1);
+
+ if (p2.get_type() != Variant::NIL) {
+ args.push_back(p2);
+
+ if (p3.get_type() != Variant::NIL) {
+ args.push_back(p3);
+
+ if (p4.get_type() != Variant::NIL) {
+ args.push_back(p4);
+
+ if (p5.get_type() != Variant::NIL) {
+ args.push_back(p5);
+ }
+ }
+ }
+ }
+ }
+
+ String new_string;
+
+ int findex = 0;
+ int search_from = 0;
+ int result = 0;
+
+ while ((result = sfind(p_text, search_from)) >= 0) {
+ CharType c = p_text[result + 1];
+
+ int req_index = (c == 's' ? findex++ : c - '0');
+
+ new_string += p_text.substr(search_from, result - search_from);
+ new_string += args[req_index].operator String();
+ search_from = result + 2;
+ }
+
+ new_string += p_text.substr(search_from, p_text.length() - search_from);
+
+ return new_string;
+}
+
+bool is_csharp_keyword(const String &p_name) {
+
+ // Reserved keywords
+
+ return p_name == "abstract" || p_name == "as" || p_name == "base" || p_name == "bool" ||
+ p_name == "break" || p_name == "byte" || p_name == "case" || p_name == "catch" ||
+ p_name == "char" || p_name == "checked" || p_name == "class" || p_name == "const" ||
+ p_name == "continue" || p_name == "decimal" || p_name == "default" || p_name == "delegate" ||
+ p_name == "do" || p_name == "double" || p_name == "else" || p_name == "enum" ||
+ p_name == "event" || p_name == "explicit" || p_name == "extern" || p_name == "false" ||
+ p_name == "finally" || p_name == "fixed" || p_name == "float" || p_name == "for" ||
+ p_name == "forech" || p_name == "goto" || p_name == "if" || p_name == "implicit" ||
+ p_name == "in" || p_name == "int" || p_name == "interface" || p_name == "internal" ||
+ p_name == "is" || p_name == "lock" || p_name == "long" || p_name == "namespace" ||
+ p_name == "new" || p_name == "null" || p_name == "object" || p_name == "operator" ||
+ p_name == "out" || p_name == "override" || p_name == "params" || p_name == "private" ||
+ p_name == "protected" || p_name == "public" || p_name == "readonly" || p_name == "ref" ||
+ p_name == "return" || p_name == "sbyte" || p_name == "sealed" || p_name == "short" ||
+ p_name == "sizeof" || p_name == "stackalloc" || p_name == "static" || p_name == "string" ||
+ p_name == "struct" || p_name == "switch" || p_name == "this" || p_name == "throw" ||
+ p_name == "true" || p_name == "try" || p_name == "typeof" || p_name == "uint" || p_name == "ulong" ||
+ p_name == "unchecked" || p_name == "unsafe" || p_name == "ushort" || p_name == "using" ||
+ p_name == "virtual" || p_name == "volatile" || p_name == "void" || p_name == "while";
+}
+
+String escape_csharp_keyword(const String &p_name) {
+ return is_csharp_keyword(p_name) ? "@" + p_name : p_name;
+}
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
new file mode 100644
index 0000000000..a0d66ebdc3
--- /dev/null
+++ b/modules/mono/utils/string_utils.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* string_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef STRING_FORMAT_H
+#define STRING_FORMAT_H
+
+#include "ustring.h"
+#include "variant.h"
+
+String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
+
+#ifdef TOOLS_ENABLED
+bool is_csharp_keyword(const String &p_name);
+
+String escape_csharp_keyword(const String &p_name);
+#endif
+
+#endif // STRING_FORMAT_H
diff --git a/modules/ogg/SCsub b/modules/ogg/SCsub
index 5eabaf6f2b..5e559bd4db 100644
--- a/modules/ogg/SCsub
+++ b/modules/ogg/SCsub
@@ -6,7 +6,7 @@ Import('env_modules')
env_ogg = env_modules.Clone()
# Thirdparty source files
-if (env['builtin_libogg'] != 'no'):
+if env['builtin_libogg']:
thirdparty_dir = "#thirdparty/libogg/"
thirdparty_sources = [
"bitwise.c",
diff --git a/modules/openssl/SCsub b/modules/openssl/SCsub
index eb3c0e64d8..84c5e68439 100644
--- a/modules/openssl/SCsub
+++ b/modules/openssl/SCsub
@@ -6,7 +6,7 @@ Import('env_modules')
env_openssl = env_modules.Clone()
# Thirdparty source files
-if (env['builtin_openssl'] != 'no'):
+if env['builtin_openssl']:
thirdparty_dir = "#thirdparty/openssl/"
thirdparty_sources = [
diff --git a/modules/openssl/stream_peer_openssl.cpp b/modules/openssl/stream_peer_openssl.cpp
index d40bf73883..6d1d5485f3 100644
--- a/modules/openssl/stream_peer_openssl.cpp
+++ b/modules/openssl/stream_peer_openssl.cpp
@@ -29,6 +29,17 @@
/*************************************************************************/
#include "stream_peer_openssl.h"
+// Compatibility with OpenSSL 1.1.0.
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#define BIO_set_num(b, n)
+#else
+#define BIO_set_num(b, n) ((b)->num = (n))
+
+#define BIO_set_init(b, i) ((b)->init = (i))
+#define BIO_set_data(b, p) ((b)->ptr = (p))
+#define BIO_get_data(b) ((b)->ptr)
+#endif
+
//hostname matching code from curl
bool StreamPeerOpenSSL::_match_host_name(const char *name, const char *hostname) {
@@ -157,10 +168,10 @@ int StreamPeerOpenSSL::_cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg
}
int StreamPeerOpenSSL::_bio_create(BIO *b) {
- b->init = 1;
- b->num = 0;
- b->ptr = NULL;
- b->flags = 0;
+ BIO_set_init(b, 1);
+ BIO_set_num(b, 0);
+ BIO_set_data(b, NULL);
+ BIO_clear_flags(b, ~0);
return 1;
}
@@ -168,9 +179,9 @@ int StreamPeerOpenSSL::_bio_destroy(BIO *b) {
if (b == NULL)
return 0;
- b->ptr = NULL; /* sb_tls_remove() will free it */
- b->init = 0;
- b->flags = 0;
+ BIO_set_data(b, NULL); /* sb_tls_remove() will free it */
+ BIO_set_init(b, 0);
+ BIO_clear_flags(b, ~0);
return 1;
}
@@ -178,7 +189,7 @@ int StreamPeerOpenSSL::_bio_read(BIO *b, char *buf, int len) {
if (buf == NULL || len <= 0) return 0;
- StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)b->ptr;
+ StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)BIO_get_data(b);
ERR_FAIL_COND_V(sp == NULL, 0);
@@ -212,7 +223,7 @@ int StreamPeerOpenSSL::_bio_write(BIO *b, const char *buf, int len) {
if (buf == NULL || len <= 0) return 0;
- StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)b->ptr;
+ StreamPeerOpenSSL *sp = (StreamPeerOpenSSL *)BIO_get_data(b);
ERR_FAIL_COND_V(sp == NULL, 0);
@@ -258,6 +269,26 @@ int StreamPeerOpenSSL::_bio_puts(BIO *b, const char *str) {
return _bio_write(b, str, strlen(str));
}
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+BIO_METHOD *StreamPeerOpenSSL::_bio_method = NULL;
+
+BIO_METHOD *StreamPeerOpenSSL::_get_bio_method() {
+ if (_bio_method) // already initialized.
+ return _bio_method;
+
+ /* it's a source/sink BIO */
+ _bio_method = BIO_meth_new(100 | 0x400, "streampeer glue");
+ BIO_meth_set_write(_bio_method, _bio_write);
+ BIO_meth_set_read(_bio_method, _bio_read);
+ BIO_meth_set_puts(_bio_method, _bio_puts);
+ BIO_meth_set_gets(_bio_method, _bio_gets);
+ BIO_meth_set_ctrl(_bio_method, _bio_ctrl);
+ BIO_meth_set_create(_bio_method, _bio_create);
+ BIO_meth_set_destroy(_bio_method, _bio_destroy);
+
+ return _bio_method;
+}
+#else
BIO_METHOD StreamPeerOpenSSL::_bio_method = {
/* it's a source/sink BIO */
(100 | 0x400),
@@ -271,6 +302,11 @@ BIO_METHOD StreamPeerOpenSSL::_bio_method = {
_bio_destroy
};
+BIO_METHOD *StreamPeerOpenSSL::_get_bio_method() {
+ return &_bio_method;
+}
+#endif
+
Error StreamPeerOpenSSL::connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs, const String &p_for_hostname) {
if (connected)
@@ -330,8 +366,8 @@ Error StreamPeerOpenSSL::connect_to_stream(Ref<StreamPeer> p_base, bool p_valida
}
ssl = SSL_new(ctx);
- bio = BIO_new(&_bio_method);
- bio->ptr = this;
+ bio = BIO_new(_get_bio_method());
+ BIO_set_data(bio, this);
SSL_set_bio(ssl, bio, bio);
if (p_for_hostname != String()) {
@@ -532,7 +568,9 @@ void StreamPeerOpenSSL::initialize_ssl() {
load_certs_func = _load_certs;
_create = _create_func;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
+#endif
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
ERR_load_BIO_strings(); // Load BIO error strings
diff --git a/modules/openssl/stream_peer_openssl.h b/modules/openssl/stream_peer_openssl.h
index 1e445ef681..ad09564447 100644
--- a/modules/openssl/stream_peer_openssl.h
+++ b/modules/openssl/stream_peer_openssl.h
@@ -53,7 +53,12 @@ private:
static int _bio_gets(BIO *b, char *buf, int len);
static int _bio_puts(BIO *b, const char *str);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ static BIO_METHOD *_bio_method;
+#else
static BIO_METHOD _bio_method;
+#endif
+ static BIO_METHOD *_get_bio_method();
static bool _match_host_name(const char *name, const char *hostname);
static Error _match_common_name(const char *hostname, const X509 *server_cert);
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index 4d3053c7ec..fee06bd267 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -6,7 +6,7 @@ Import('env_modules')
env_opus = env_modules.Clone()
# Thirdparty source files
-if (env['builtin_opus'] != 'no'):
+if env['builtin_opus']:
thirdparty_dir = "#thirdparty/opus/"
thirdparty_sources = [
@@ -209,7 +209,7 @@ if (env['builtin_opus'] != 'no'):
env_opus.Append(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths])
# also requires libogg
- if (env['builtin_libogg'] != 'no'):
+ if env['builtin_libogg']:
env_opus.Append(CPPPATH=["#thirdparty/libogg"])
# Module files
diff --git a/modules/opus/audio_stream_opus.cpp b/modules/opus/audio_stream_opus.cpp
index 1dac890eb8..06eab4c94d 100644
--- a/modules/opus/audio_stream_opus.cpp
+++ b/modules/opus/audio_stream_opus.cpp
@@ -56,7 +56,7 @@ int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, in
fa->seek(_offset);
} break;
case SEEK_CUR: {
- fa->seek(fa->get_pos() + _offset);
+ fa->seek(fa->get_position() + _offset);
} break;
case SEEK_END: {
fa->seek_end(_offset);
@@ -83,7 +83,7 @@ int AudioStreamPlaybackOpus::_op_close_func(void *_stream) {
opus_int64 AudioStreamPlaybackOpus::_op_tell_func(void *_stream) {
FileAccess *_fa = (FileAccess *)_stream;
- return (opus_int64)_fa->get_pos();
+ return (opus_int64)_fa->get_position();
}
void AudioStreamPlaybackOpus::_clear_stream() {
@@ -247,7 +247,7 @@ void AudioStreamPlaybackOpus::play(float p_from) {
frames_mixed = pre_skip;
playing = true;
if (p_from > 0) {
- seek_pos(p_from);
+ seek(p_from);
}
}
@@ -256,7 +256,7 @@ void AudioStreamPlaybackOpus::stop() {
playing = false;
}
-void AudioStreamPlaybackOpus::seek_pos(float p_time) {
+void AudioStreamPlaybackOpus::seek(float p_time) {
if (!playing) return;
ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate);
bool ok = op_pcm_seek(opus_file, pcm_offset) == 0;
@@ -267,7 +267,7 @@ void AudioStreamPlaybackOpus::seek_pos(float p_time) {
frames_mixed = osrate * p_time;
}
-int AudioStreamPlaybackOpus::mix(int16_t *p_bufer, int p_frames) {
+int AudioStreamPlaybackOpus::mix(int16_t *p_buffer, int p_frames) {
if (!playing)
return 0;
@@ -281,7 +281,7 @@ int AudioStreamPlaybackOpus::mix(int16_t *p_bufer, int p_frames) {
break;
}
- int ret = op_read(opus_file, (opus_int16 *)p_bufer, todo * stream_channels, &current_section);
+ int ret = op_read(opus_file, (opus_int16 *)p_buffer, todo * stream_channels, &current_section);
if (ret < 0) {
playing = false;
ERR_EXPLAIN("Error reading Opus File: " + file);
@@ -325,7 +325,7 @@ int AudioStreamPlaybackOpus::mix(int16_t *p_bufer, int p_frames) {
frames_mixed += ret;
- p_bufer += ret * stream_channels;
+ p_buffer += ret * stream_channels;
p_frames -= ret;
}
@@ -340,7 +340,7 @@ float AudioStreamPlaybackOpus::get_length() const {
return length;
}
-float AudioStreamPlaybackOpus::get_pos() const {
+float AudioStreamPlaybackOpus::get_playback_position() const {
int32_t frames = int32_t(frames_mixed);
if (frames < 0)
diff --git a/modules/opus/audio_stream_opus.h b/modules/opus/audio_stream_opus.h
index ccfe04e84e..f8d8f585cf 100644
--- a/modules/opus/audio_stream_opus.h
+++ b/modules/opus/audio_stream_opus.h
@@ -99,15 +99,15 @@ public:
virtual int get_loop_count() const { return repeats; }
- virtual float get_pos() const;
- virtual void seek_pos(float p_time);
+ virtual float get_playback_position() const;
+ virtual void seek(float p_time);
virtual int get_channels() const { return stream_channels; }
virtual int get_mix_rate() const { return osrate; }
virtual int get_minimum_buffer_size() const;
- virtual int mix(int16_t *p_bufer, int p_frames);
+ virtual int mix(int16_t *p_buffer, int p_frames);
AudioStreamPlaybackOpus();
~AudioStreamPlaybackOpus();
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index 90ee164b6f..03592047ad 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -74,7 +74,7 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path,
uint32_t mipmaps = f->get_32();
uint32_t flags = f->get_32();
uint32_t surfsize = f->get_32();
- f->seek(f->get_pos() + 20); // bpp, rmask, gmask, bmask, amask
+ f->seek(f->get_position() + 20); // bpp, rmask, gmask, bmask, amask
uint8_t pvrid[5] = { 0, 0, 0, 0, 0 };
f->get_buffer(pvrid, 4);
ERR_FAIL_COND_V(String((char *)pvrid) != "PVR!", RES());
diff --git a/modules/recast/SCsub b/modules/recast/SCsub
index 349bd22efb..500c0ec055 100644
--- a/modules/recast/SCsub
+++ b/modules/recast/SCsub
@@ -5,7 +5,7 @@ Import('env')
# Not building in a separate env as core needs it
# Thirdparty source files
-if (env['builtin_recast'] != 'no'):
+if env['builtin_recast']:
thirdparty_dir = "#thirdparty/recastnavigation/Recast/"
thirdparty_sources = [
"Source/Recast.cpp",
@@ -24,10 +24,6 @@ if (env['builtin_recast'] != 'no'):
env.Append(CPPPATH=[thirdparty_dir, thirdparty_dir + "/Include"])
- # also requires recast headers
- if (env['builtin_recast'] != 'no'):
- env.Append(CPPPATH=["#thirdparty/recastnavigation/Recast"])
-
lib = env.Library("recast_builtin", thirdparty_sources)
env.Append(LIBS=[lib])
diff --git a/modules/recast/config.py b/modules/recast/config.py
index fb920482f5..d42f07b2a9 100644
--- a/modules/recast/config.py
+++ b/modules/recast/config.py
@@ -1,6 +1,6 @@
def can_build(platform):
- return True
+ return platform != "android"
def configure(env):
diff --git a/modules/regex/SCsub b/modules/regex/SCsub
index 2dfc2739e9..18b4051afe 100644
--- a/modules/regex/SCsub
+++ b/modules/regex/SCsub
@@ -7,8 +7,8 @@ env_regex = env_modules.Clone()
env_regex.Append(CPPFLAGS=["-DPCRE2_CODE_UNIT_WIDTH=0"])
env_regex.add_source_files(env.modules_sources, "*.cpp")
-if (env['builtin_pcre2'] != 'no'):
- jit_blacklist = ['javascript']
+if env['builtin_pcre2']:
+ jit_blacklist = ['javascript', 'uwp']
thirdparty_dir = '#thirdparty/pcre2/src/'
thirdparty_flags = ['-DPCRE2_STATIC', '-DHAVE_CONFIG_H']
if 'platform' in env and env['platform'] not in jit_blacklist:
diff --git a/modules/squish/SCsub b/modules/squish/SCsub
index cca7c038f1..127f22d798 100644
--- a/modules/squish/SCsub
+++ b/modules/squish/SCsub
@@ -6,7 +6,7 @@ Import('env_modules')
env_squish = env_modules.Clone()
# Thirdparty source files
-if (env['builtin_squish'] != 'no'):
+if env['builtin_squish']:
thirdparty_dir = "#thirdparty/squish/"
thirdparty_sources = [
"alpha.cpp",
diff --git a/modules/squish/config.py b/modules/squish/config.py
index cc8f098010..9b7729bda4 100644
--- a/modules/squish/config.py
+++ b/modules/squish/config.py
@@ -6,6 +6,6 @@ def can_build(platform):
def configure(env):
# Tools only, disabled for non-tools
# TODO: Find a cleaner way to achieve that
- if (env["tools"] == "no"):
- env["module_squish_enabled"] = "no"
+ if not env['tools']:
+ env['module_squish_enabled'] = False
env.disabled_modules.append("squish")
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index 9457fbfaf6..5c252bda86 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -58,7 +58,7 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra
//end of file!
if (vorbis_stream->loop) {
//loop
- seek_pos(vorbis_stream->loop_offset);
+ seek(vorbis_stream->loop_offset);
loops++;
} else {
for (int i = mixed; i < p_frames; i++) {
@@ -78,7 +78,7 @@ float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() {
void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) {
active = true;
- seek_pos(p_from_pos);
+ seek(p_from_pos);
loops = 0;
_begin_resample();
}
@@ -97,11 +97,11 @@ int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
return loops;
}
-float AudioStreamPlaybackOGGVorbis::get_pos() const {
+float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
return float(frames_mixed) / vorbis_stream->sample_rate;
}
-void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) {
+void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
if (!active)
return;
@@ -129,7 +129,6 @@ AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
Ref<AudioStreamPlaybackOGGVorbis> ovs;
- printf("instance at %p, data %p\n", this, data);
ERR_FAIL_COND_V(data == NULL, ovs);
@@ -208,8 +207,6 @@ void AudioStreamOGGVorbis::set_data(const PoolVector<uint8_t> &p_data) {
break;
}
}
-
- printf("create at %p, data %p\n", this, data);
}
PoolVector<uint8_t> AudioStreamOGGVorbis::get_data() const {
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.h b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
index bcd829a56a..f4d381897b 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.h
@@ -67,8 +67,8 @@ public:
virtual int get_loop_count() const; //times it looped
- virtual float get_pos() const;
- virtual void seek_pos(float p_time);
+ virtual float get_playback_position() const;
+ virtual void seek(float p_time);
virtual float get_length() const; //if supported, otherwise return 0
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index e27452354b..9c198ea98e 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -51,7 +51,7 @@ inline void change_nsvg_paint_color(NSVGpaint *p_paint, const uint32_t p_old, co
if (p_paint->type == NSVG_PAINT_COLOR) {
if (p_paint->color << 8 == p_old << 8) {
- p_paint->color = p_new;
+ p_paint->color = (p_paint->color & 0xFF000000) | (p_new & 0x00FFFFFF);
}
}
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 7c7cf5bcbe..d7a1ce7308 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -253,7 +253,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
err = FAILED;
if (err == OK) {
- f->seek(f->get_pos() + tga_header.id_length);
+ f->seek(f->get_position() + tga_header.id_length);
PoolVector<uint8_t> palette;
@@ -269,7 +269,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
}
PoolVector<uint8_t>::Write src_image_w = src_image.write();
- f->get_buffer(&src_image_w[0], src_image_len - f->get_pos());
+ f->get_buffer(&src_image_w[0], src_image_len - f->get_position());
PoolVector<uint8_t>::Read src_image_r = src_image.read();
diff --git a/modules/theora/SCsub b/modules/theora/SCsub
index 2de4d29640..9015c2c354 100644
--- a/modules/theora/SCsub
+++ b/modules/theora/SCsub
@@ -6,7 +6,7 @@ Import('env_modules')
env_theora = env_modules.Clone()
# Thirdparty source files
-if (env['builtin_libtheora'] != 'no'):
+if env['builtin_libtheora']:
thirdparty_dir = "#thirdparty/libtheora/"
thirdparty_sources = [
#"analyze.c",
@@ -74,9 +74,9 @@ if (env['builtin_libtheora'] != 'no'):
env_theora.Append(CPPPATH=[thirdparty_dir])
# also requires libogg and libvorbis
- if (env['builtin_libogg'] != 'no'):
+ if env['builtin_libogg']:
env_theora.Append(CPPPATH=["#thirdparty/libogg"])
- if (env['builtin_libvorbis'] != 'no'):
+ if env['builtin_libvorbis']:
env_theora.Append(CPPPATH=["#thirdparty/libvorbis"])
# Godot source files
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 02b994f8db..c75bec31df 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -634,12 +634,12 @@ int VideoStreamPlaybackTheora::get_loop_count() const {
return 0;
};
-float VideoStreamPlaybackTheora::get_pos() const {
+float VideoStreamPlaybackTheora::get_playback_position() const {
return get_time();
};
-void VideoStreamPlaybackTheora::seek_pos(float p_time){
+void VideoStreamPlaybackTheora::seek(float p_time){
// no
};
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index f04e49c662..484a1a7fb9 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -140,8 +140,8 @@ public:
virtual int get_loop_count() const;
- virtual float get_pos() const;
- virtual void seek_pos(float p_time);
+ virtual float get_playback_position() const;
+ virtual void seek(float p_time);
void set_file(const String &p_file);
diff --git a/modules/tinyexr/config.py b/modules/tinyexr/config.py
index 2e4b96a6b0..3e16fd725e 100644
--- a/modules/tinyexr/config.py
+++ b/modules/tinyexr/config.py
@@ -6,6 +6,6 @@ def can_build(platform):
def configure(env):
# Tools only, disabled for non-tools
# TODO: Find a cleaner way to achieve that
- if (env["tools"] == "no"):
- env["module_tinyexr_enabled"] = "no"
+ if not env['tools']:
+ env['module_tinyexr_enabled'] = False
env.disabled_modules.append("tinyexr")
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 88012d2031..765fe4c2f2 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -125,6 +125,7 @@ void VisualScriptNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_visual_script"), &VisualScriptNode::get_visual_script);
ClassDB::bind_method(D_METHOD("set_default_input_value", "port_idx", "value"), &VisualScriptNode::set_default_input_value);
ClassDB::bind_method(D_METHOD("get_default_input_value", "port_idx"), &VisualScriptNode::get_default_input_value);
+ ClassDB::bind_method(D_METHOD("ports_changed_notify"), &VisualScriptNode::ports_changed_notify);
ClassDB::bind_method(D_METHOD("_set_default_input_values", "values"), &VisualScriptNode::_set_default_input_values);
ClassDB::bind_method(D_METHOD("_get_default_input_values"), &VisualScriptNode::_get_default_input_values);
@@ -423,7 +424,7 @@ Ref<VisualScriptNode> VisualScript::get_node(const StringName &p_func, int p_id)
return func.nodes[p_id].node;
}
-void VisualScript::set_node_pos(const StringName &p_func, int p_id, const Point2 &p_pos) {
+void VisualScript::set_node_position(const StringName &p_func, int p_id, const Point2 &p_pos) {
ERR_FAIL_COND(instances.size());
ERR_FAIL_COND(!functions.has(p_func));
@@ -433,7 +434,7 @@ void VisualScript::set_node_pos(const StringName &p_func, int p_id, const Point2
func.nodes[p_id].pos = p_pos;
}
-Point2 VisualScript::get_node_pos(const StringName &p_func, int p_id) const {
+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];
@@ -973,11 +974,6 @@ bool VisualScript::is_tool() const {
return false;
}
-String VisualScript::get_node_type() const {
-
- return String();
-}
-
ScriptLanguage *VisualScript::get_language() const {
return VisualScriptLanguage::singleton;
@@ -1273,14 +1269,14 @@ void VisualScript::_bind_methods() {
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("add_node", "func", "id", "node", "pos"), &VisualScript::add_node, DEFVAL(Point2()));
+ 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("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_pos", "func", "id", "pos"), &VisualScript::set_node_pos);
- ClassDB::bind_method(D_METHOD("get_node_pos", "func", "id"), &VisualScript::get_node_pos);
+ 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("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);
@@ -2008,8 +2004,8 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
Node *node = Object::cast_to<Node>(p_owner);
if (p_script->functions.has("_process"))
node->set_process(true);
- if (p_script->functions.has("_fixed_process"))
- node->set_fixed_process(true);
+ if (p_script->functions.has("_physics_process"))
+ node->set_physics_process(true);
if (p_script->functions.has("_input"))
node->set_process_input(true);
if (p_script->functions.has("_unhandled_input"))
@@ -2411,6 +2407,10 @@ bool VisualScriptLanguage::has_named_classes() const {
return false;
}
+bool VisualScriptLanguage::supports_builtin_mode() const {
+
+ return true;
+}
int VisualScriptLanguage::find_function(const String &p_function, const String &p_code) const {
return -1;
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 297e9e510f..0f60b103c9 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -278,8 +278,8 @@ public:
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_pos(const StringName &p_func, int p_id, const Point2 &p_pos);
- Point2 get_node_pos(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);
@@ -339,8 +339,6 @@ public:
virtual bool is_tool() const;
- virtual String get_node_type() const;
-
virtual ScriptLanguage *get_language() const;
virtual bool has_script_signal(const StringName &p_signal) const;
@@ -569,6 +567,7 @@ public:
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
+ virtual bool supports_builtin_mode() 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 PoolStringArray &p_args) const;
virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 972be5f5a4..7c9d306831 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -65,6 +65,8 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"decimals",
"stepify",
"lerp",
+ "inverse_lerp",
+ "range_lerp",
"dectime",
"randomize",
"randi",
@@ -76,6 +78,8 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"rad2deg",
"linear2db",
"db2linear",
+ "wrapi",
+ "wrapf",
"max",
"min",
"clamp",
@@ -194,9 +198,14 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
case COLORN:
return 2;
case MATH_LERP:
+ case MATH_INVERSE_LERP:
case MATH_DECTIME:
+ case MATH_WRAP:
+ case MATH_WRAPF:
case LOGIC_CLAMP:
return 3;
+ case MATH_RANGE_LERP:
+ return 5;
case FUNC_MAX: {
}
}
@@ -297,7 +306,26 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
return PropertyInfo(Variant::REAL, "to");
else
return PropertyInfo(Variant::REAL, "weight");
-
+ } break;
+ case MATH_INVERSE_LERP: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::REAL, "from");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::REAL, "to");
+ else
+ return PropertyInfo(Variant::REAL, "value");
+ } break;
+ case MATH_RANGE_LERP: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::REAL, "value");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::REAL, "istart");
+ else if (p_idx == 2)
+ return PropertyInfo(Variant::REAL, "istop");
+ else if (p_idx == 3)
+ return PropertyInfo(Variant::REAL, "ostart");
+ else
+ return PropertyInfo(Variant::REAL, "ostop");
} break;
case MATH_DECTIME: {
if (p_idx == 0)
@@ -340,6 +368,22 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case MATH_DB2LINEAR: {
return PropertyInfo(Variant::REAL, "db");
} break;
+ case MATH_WRAP: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::INT, "value");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::INT, "min");
+ else
+ return PropertyInfo(Variant::INT, "max");
+ } break;
+ case MATH_WRAPF: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::REAL, "value");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::REAL, "min");
+ else
+ return PropertyInfo(Variant::REAL, "max");
+ } break;
case LOGIC_MAX: {
if (p_idx == 0)
return PropertyInfo(Variant::REAL, "a");
@@ -495,6 +539,8 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
} break;
case MATH_STEPIFY:
case MATH_LERP:
+ case MATH_INVERSE_LERP:
+ case MATH_RANGE_LERP:
case MATH_DECTIME: {
t = Variant::REAL;
@@ -523,9 +569,13 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
case MATH_DEG2RAD:
case MATH_RAD2DEG:
case MATH_LINEAR2DB:
+ case MATH_WRAPF:
case MATH_DB2LINEAR: {
t = Variant::REAL;
} break;
+ case MATH_WRAP: {
+ t = Variant::INT;
+ } break;
case LOGIC_MAX:
case LOGIC_MIN:
case LOGIC_CLAMP: {
@@ -795,6 +845,22 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
VALIDATE_ARG_NUM(2);
*r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
} break;
+ case VisualScriptBuiltinFunc::MATH_INVERSE_LERP: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_RANGE_LERP: {
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ VALIDATE_ARG_NUM(3);
+ VALIDATE_ARG_NUM(4);
+ *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
+ } break;
case VisualScriptBuiltinFunc::MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
@@ -856,6 +922,18 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
VALIDATE_ARG_NUM(0);
*r_return = Math::db2linear((double)*p_inputs[0]);
} break;
+ case VisualScriptBuiltinFunc::MATH_WRAP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]);
+ } break;
+ case VisualScriptBuiltinFunc::MATH_WRAPF: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case VisualScriptBuiltinFunc::LOGIC_MAX: {
if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
@@ -1203,6 +1281,8 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(MATH_DECIMALS);
BIND_ENUM_CONSTANT(MATH_STEPIFY);
BIND_ENUM_CONSTANT(MATH_LERP);
+ BIND_ENUM_CONSTANT(MATH_INVERSE_LERP);
+ BIND_ENUM_CONSTANT(MATH_RANGE_LERP);
BIND_ENUM_CONSTANT(MATH_DECTIME);
BIND_ENUM_CONSTANT(MATH_RANDOMIZE);
BIND_ENUM_CONSTANT(MATH_RAND);
@@ -1214,6 +1294,8 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(MATH_RAD2DEG);
BIND_ENUM_CONSTANT(MATH_LINEAR2DB);
BIND_ENUM_CONSTANT(MATH_DB2LINEAR);
+ BIND_ENUM_CONSTANT(MATH_WRAP);
+ BIND_ENUM_CONSTANT(MATH_WRAPF);
BIND_ENUM_CONSTANT(LOGIC_MAX);
BIND_ENUM_CONSTANT(LOGIC_MIN);
BIND_ENUM_CONSTANT(LOGIC_CLAMP);
@@ -1236,6 +1318,11 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_MAX);
}
+VisualScriptBuiltinFunc::VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func) {
+
+ this->func = func;
+}
+
VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() {
func = MATH_SIN;
@@ -1244,9 +1331,7 @@ VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() {
template <VisualScriptBuiltinFunc::BuiltinFunc func>
static Ref<VisualScriptNode> create_builtin_func_node(const String &p_name) {
- Ref<VisualScriptBuiltinFunc> node;
- node.instance();
- node->set_func(func);
+ Ref<VisualScriptBuiltinFunc> node = memnew(VisualScriptBuiltinFunc(func));
return node;
}
@@ -1282,6 +1367,8 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/decimals", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_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/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>);
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>);
@@ -1294,6 +1381,8 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAPF>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/max", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/min", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>);
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
index 97ab307039..34a2825938 100644
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -64,6 +64,8 @@ public:
MATH_DECIMALS,
MATH_STEPIFY,
MATH_LERP,
+ MATH_INVERSE_LERP,
+ MATH_RANGE_LERP,
MATH_DECTIME,
MATH_RANDOMIZE,
MATH_RAND,
@@ -75,6 +77,8 @@ public:
MATH_RAD2DEG,
MATH_LINEAR2DB,
MATH_DB2LINEAR,
+ MATH_WRAP,
+ MATH_WRAPF,
LOGIC_MAX,
LOGIC_MIN,
LOGIC_CLAMP,
@@ -130,6 +134,7 @@ public:
virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance);
+ VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func);
VisualScriptBuiltinFunc();
};
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 671a507377..03015df844 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -331,44 +331,83 @@ public:
VisualScriptEditorVariableEdit() { undo_redo = NULL; }
};
-static Color _color_from_type(Variant::Type p_type) {
+static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
Color color;
- switch (p_type) {
- case Variant::NIL: color = Color::html("69ecbd"); break;
-
- case Variant::BOOL: color = Color::html("8da6f0"); break;
- case Variant::INT: color = Color::html("7dc6ef"); break;
- case Variant::REAL: color = Color::html("61daf4"); break;
- case Variant::STRING: color = Color::html("6ba7ec"); break;
-
- case Variant::VECTOR2: color = Color::html("bd91f1"); break;
- case Variant::RECT2: color = Color::html("f191a5"); break;
- case Variant::VECTOR3: color = Color::html("d67dee"); break;
- case Variant::TRANSFORM2D: color = Color::html("c4ec69"); break;
- case Variant::PLANE: color = Color::html("f77070"); break;
- case Variant::QUAT: color = Color::html("ec69a3"); break;
- case Variant::RECT3: color = Color::html("ee7991"); break;
- case Variant::BASIS: color = Color::html("e3ec69"); break;
- case Variant::TRANSFORM: color = Color::html("f6a86e"); break;
-
- case Variant::COLOR: color = Color::html("9dff70"); break;
- case Variant::NODE_PATH: color = Color::html("6993ec"); break;
- case Variant::_RID: color = Color::html("69ec9a"); break;
- case Variant::OBJECT: color = Color::html("79f3e8"); break;
- case Variant::DICTIONARY: color = Color::html("77edb1"); break;
-
- case Variant::ARRAY: color = Color::html("e0e0e0"); break;
- case Variant::POOL_BYTE_ARRAY: color = Color::html("aaf4c8"); break;
- case Variant::POOL_INT_ARRAY: color = Color::html("afdcf5"); break;
- case Variant::POOL_REAL_ARRAY: color = Color::html("97e7f8"); break;
- case Variant::POOL_STRING_ARRAY: color = Color::html("9dc4f2"); break;
- case Variant::POOL_VECTOR2_ARRAY: color = Color::html("d1b3f5"); break;
- case Variant::POOL_VECTOR3_ARRAY: color = Color::html("df9bf2"); break;
- case Variant::POOL_COLOR_ARRAY: color = Color::html("e9ff97"); break;
-
- default:
- color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.7, 0.7);
- }
+ if (dark_theme)
+ switch (p_type) {
+ case Variant::NIL: color = Color::html("#69ecbd"); break;
+
+ case Variant::BOOL: color = Color::html("#8da6f0"); break;
+ case Variant::INT: color = Color::html("#7dc6ef"); break;
+ case Variant::REAL: color = Color::html("#61daf4"); break;
+ case Variant::STRING: color = Color::html("#6ba7ec"); break;
+
+ case Variant::VECTOR2: color = Color::html("#bd91f1"); break;
+ case Variant::RECT2: color = Color::html("#f191a5"); break;
+ case Variant::VECTOR3: color = Color::html("#d67dee"); break;
+ case Variant::TRANSFORM2D: color = Color::html("#c4ec69"); break;
+ case Variant::PLANE: color = Color::html("#f77070"); break;
+ case Variant::QUAT: color = Color::html("#ec69a3"); break;
+ case Variant::RECT3: color = Color::html("#ee7991"); break;
+ case Variant::BASIS: color = Color::html("#e3ec69"); break;
+ case Variant::TRANSFORM: color = Color::html("#f6a86e"); break;
+
+ case Variant::COLOR: color = Color::html("#9dff70"); break;
+ case Variant::NODE_PATH: color = Color::html("#6993ec"); break;
+ case Variant::_RID: color = Color::html("#69ec9a"); break;
+ case Variant::OBJECT: color = Color::html("#79f3e8"); break;
+ case Variant::DICTIONARY: color = Color::html("#77edb1"); break;
+
+ case Variant::ARRAY: color = Color::html("#e0e0e0"); break;
+ case Variant::POOL_BYTE_ARRAY: color = Color::html("#aaf4c8"); break;
+ case Variant::POOL_INT_ARRAY: color = Color::html("#afdcf5"); break;
+ case Variant::POOL_REAL_ARRAY: color = Color::html("#97e7f8"); break;
+ case Variant::POOL_STRING_ARRAY: color = Color::html("#9dc4f2"); break;
+ case Variant::POOL_VECTOR2_ARRAY: color = Color::html("#d1b3f5"); break;
+ case Variant::POOL_VECTOR3_ARRAY: color = Color::html("#df9bf2"); break;
+ case Variant::POOL_COLOR_ARRAY: color = Color::html("#e9ff97"); break;
+
+ default:
+ color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.7, 0.7);
+ }
+ else
+ switch (p_type) {
+ case Variant::NIL: color = Color::html("#25e3a0"); break;
+
+ case Variant::BOOL: color = Color::html("#6d8eeb"); break;
+ case Variant::INT: color = Color::html("#4fb2e9"); break;
+ case Variant::REAL: color = Color::html("#27ccf0"); break;
+ case Variant::STRING: color = Color::html("#4690e7"); break;
+
+ case Variant::VECTOR2: color = Color::html("#ad76ee"); break;
+ case Variant::RECT2: color = Color::html("#ee758e"); break;
+ case Variant::VECTOR3: color = Color::html("#dc6aed"); break;
+ case Variant::TRANSFORM2D: color = Color::html("#96ce1a"); break;
+ case Variant::PLANE: color = Color::html("#f77070"); break;
+ case Variant::QUAT: color = Color::html("#ec69a3"); break;
+ case Variant::RECT3: color = Color::html("#ee7991"); break;
+ case Variant::BASIS: color = Color::html("#b2bb19"); break;
+ case Variant::TRANSFORM: color = Color::html("#f49047"); break;
+
+ case Variant::COLOR: color = Color::html("#3cbf00"); break;
+ case Variant::NODE_PATH: color = Color::html("#6993ec"); break;
+ case Variant::_RID: color = Color::html("#2ce573"); break;
+ case Variant::OBJECT: color = Color::html("#12d5c3"); break;
+ case Variant::DICTIONARY: color = Color::html("#57e99f"); break;
+
+ case Variant::ARRAY: color = Color::html("#737373"); break;
+ case Variant::POOL_BYTE_ARRAY: color = Color::html("#61ea98"); break;
+ case Variant::POOL_INT_ARRAY: color = Color::html("#61baeb"); break;
+ case Variant::POOL_REAL_ARRAY: color = Color::html("#40d3f2"); break;
+ case Variant::POOL_STRING_ARRAY: color = Color::html("#609fea"); break;
+ case Variant::POOL_VECTOR2_ARRAY: color = Color::html("#9d5dea"); break;
+ case Variant::POOL_VECTOR3_ARRAY: color = Color::html("#ca5aea"); break;
+ case Variant::POOL_COLOR_ARRAY: color = Color::html("#92ba00"); break;
+
+ default:
+ color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.3, 0.3);
+ }
+
return color;
}
@@ -481,7 +520,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
continue;
Ref<VisualScriptNode> node = script->get_node(edited_func, E->get());
- Vector2 pos = script->get_node_pos(edited_func, E->get());
+ Vector2 pos = script->get_node_position(edited_func, E->get());
GraphNode *gnode = memnew(GraphNode);
gnode->set_title(node->get_caption());
@@ -491,10 +530,6 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);
}
- if (node_styles.has(node->get_category())) {
- gnode->add_style_override("frame", node_styles[node->get_category()]);
- }
-
gnode->set_meta("__vnode", node);
gnode->set_name(itos(E->get()));
gnode->connect("dragged", this, "_node_moved", varray(E->get()));
@@ -527,10 +562,31 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
gnode->connect("resize_request", this, "_comment_node_resized", varray(E->get()));
}
+ 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(MARGIN_TOP);
+ c.a = 1;
+ if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
+ Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
+ mono_color.a = 0.85;
+ c = mono_color;
+ }
+
+ gnode->add_color_override("title_color", c);
+ c.a = 0.7;
+ gnode->add_color_override("close_color", c);
+ gnode->add_style_override("frame", sbf);
+ }
+
+ const Color mono_color = get_color("mono_color", "Editor");
+
int slot_idx = 0;
bool single_seq_output = node->get_output_sequence_port_count() == 1 && node->get_output_sequence_port_text(0) == String();
- gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, Color(1, 1, 1, 1), single_seq_output, TYPE_SEQUENCE, Color(1, 1, 1, 1), seq_port, seq_port);
+ gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, mono_color, single_seq_output, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
gnode->set_offset(pos * EDSCALE);
slot_idx++;
@@ -547,7 +603,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
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, Color(1, 1, 1, 1), seq_port, seq_port);
+ gnode->set_slot(slot_idx, false, 0, Color(), true, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
slot_idx++;
}
}
@@ -662,10 +718,11 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
gnode->add_child(hbc);
+ bool dark_theme = get_constant("dark_theme", "Editor");
if (i < mixed_seq_ports) {
- gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type), true, TYPE_SEQUENCE, Color(1, 1, 1, 1), Ref<Texture>(), seq_port);
+ gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture>(), seq_port);
} else {
- gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type), right_ok, right_type, _color_from_type(right_type));
+ 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++;
@@ -695,7 +752,7 @@ void VisualScriptEditor::_update_members() {
functions->set_text(0, TTR("Functions:"));
functions->add_button(0, Control::get_icon("Override", "EditorIcons"), 1);
functions->add_button(0, Control::get_icon("Add", "EditorIcons"), 0);
- functions->set_custom_bg_color(0, Control::get_color("prop_section", "Editor"));
+ functions->set_custom_color(0, Control::get_color("mono_color", "Editor"));
List<StringName> func_names;
script->get_function_list(&func_names);
@@ -704,13 +761,7 @@ void VisualScriptEditor::_update_members() {
ti->set_text(0, E->get());
ti->set_selectable(0, true);
ti->set_editable(0, true);
- //ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); function arguments are in the node now
- //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1);
ti->set_metadata(0, E->get());
- if (E->get() == edited_func) {
- ti->set_custom_bg_color(0, get_color("prop_category", "Editor"));
- ti->set_custom_color(0, Color(1, 1, 1, 1));
- }
if (selected == E->get())
ti->select(0);
}
@@ -719,7 +770,7 @@ void VisualScriptEditor::_update_members() {
variables->set_selectable(0, false);
variables->set_text(0, TTR("Variables:"));
variables->add_button(0, Control::get_icon("Add", "EditorIcons"));
- variables->set_custom_bg_color(0, Control::get_color("prop_section", "Editor"));
+ variables->set_custom_color(0, Control::get_color("mono_color", "Editor"));
Ref<Texture> type_icons[Variant::VARIANT_MAX] = {
Control::get_icon("MiniVariant", "EditorIcons"),
@@ -758,13 +809,11 @@ void VisualScriptEditor::_update_members() {
ti->set_text(0, E->get());
Variant var = script->get_variable_default_value(E->get());
- ti->set_suffix(0, "=" + String(var));
+ ti->set_suffix(0, "= " + String(var));
ti->set_icon(0, type_icons[script->get_variable_info(E->get()).type]);
ti->set_selectable(0, true);
ti->set_editable(0, true);
- //ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0);
- //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1);
ti->set_metadata(0, E->get());
if (selected == E->get())
ti->select(0);
@@ -774,7 +823,7 @@ void VisualScriptEditor::_update_members() {
_signals->set_selectable(0, false);
_signals->set_text(0, TTR("Signals:"));
_signals->add_button(0, Control::get_icon("Add", "EditorIcons"));
- _signals->set_custom_bg_color(0, Control::get_color("prop_section", "Editor"));
+ _signals->set_custom_color(0, Control::get_color("mono_color", "Editor"));
List<StringName> signal_names;
script->get_custom_signal_list(&signal_names);
@@ -783,8 +832,6 @@ void VisualScriptEditor::_update_members() {
ti->set_text(0, E->get());
ti->set_selectable(0, true);
ti->set_editable(0, true);
- //ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0);
- //ti->add_button(0, Control::get_icon("Del", "EditorIcons"), 1);
ti->set_metadata(0, E->get());
if (selected == E->get())
ti->select(0);
@@ -1050,7 +1097,7 @@ void VisualScriptEditor::_available_node_doubleclicked() {
List<int> existing;
script->get_node_list(edited_func, &existing);
for (List<int>::Element *E = existing.front(); E; E = E->next()) {
- Point2 pos = script->get_node_pos(edited_func, E->get());
+ Point2 pos = script->get_node_position(edited_func, E->get());
if (pos.distance_to(ofs) < 15) {
ofs += Vector2(graph->get_snap(), graph->get_snap());
exists = true;
@@ -1171,7 +1218,7 @@ void VisualScriptEditor::_on_nodes_delete() {
for (List<int>::Element *F = to_erase.front(); F; F = F->next()) {
undo_redo->add_do_method(script.ptr(), "remove_node", edited_func, F->get());
- undo_redo->add_undo_method(script.ptr(), "add_node", edited_func, F->get(), script->get_node(edited_func, F->get()), script->get_node_pos(edited_func, F->get()));
+ undo_redo->add_undo_method(script.ptr(), "add_node", edited_func, F->get(), script->get_node(edited_func, F->get()), script->get_node_position(edited_func, F->get()));
List<VisualScript::SequenceConnection> sequence_conns;
script->get_sequence_connection_list(edited_func, &sequence_conns);
@@ -1228,7 +1275,7 @@ void VisualScriptEditor::_on_nodes_duplicate() {
int new_id = idc++;
to_select.insert(new_id);
- undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, dupe, script->get_node_pos(edited_func, F->get()) + Vector2(20, 20));
+ undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, dupe, script->get_node_position(edited_func, F->get()) + Vector2(20, 20));
undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id);
}
undo_redo->add_do_method(this, "_update_graph");
@@ -1262,7 +1309,7 @@ Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
if (p_from == nodes) {
- TreeItem *it = nodes->get_item_at_pos(p_point);
+ TreeItem *it = nodes->get_item_at_position(p_point);
if (!it)
return Variant();
String type = it->get_metadata(0);
@@ -1281,7 +1328,7 @@ Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
if (p_from == members) {
- TreeItem *it = members->get_item_at_pos(p_point);
+ TreeItem *it = members->get_item_at_position(p_point);
if (!it)
return Variant();
@@ -2182,7 +2229,7 @@ void VisualScriptEditor::_move_node(String func, int p_id, const Vector2 &p_to)
if (Object::cast_to<GraphNode>(node))
Object::cast_to<GraphNode>(node)->set_offset(p_to);
}
- script->set_node_pos(edited_func, p_id, p_to / EDSCALE);
+ script->set_node_position(edited_func, p_id, p_to / EDSCALE);
}
void VisualScriptEditor::_node_moved(Vector2 p_from, Vector2 p_to, int p_id) {
@@ -2196,7 +2243,7 @@ void VisualScriptEditor::_remove_node(int p_id) {
undo_redo->create_action(TTR("Remove VisualScript Node"));
undo_redo->add_do_method(script.ptr(), "remove_node", edited_func, p_id);
- undo_redo->add_undo_method(script.ptr(), "add_node", edited_func, p_id, script->get_node(edited_func, p_id), script->get_node_pos(edited_func, p_id));
+ undo_redo->add_undo_method(script.ptr(), "add_node", edited_func, p_id, script->get_node(edited_func, p_id), script->get_node_position(edited_func, p_id));
List<VisualScript::SequenceConnection> sequence_conns;
script->get_sequence_connection_list(edited_func, &sequence_conns);
@@ -2752,18 +2799,30 @@ void VisualScriptEditor::_notification(int p_what) {
variable_editor->connect("changed", this, "_update_members");
signal_editor->connect("changed", this, "_update_members");
+ Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
+
+ bool dark_theme = tm->get_constant("dark_theme", "Editor");
+
List<Pair<String, Color> > colors;
- colors.push_back(Pair<String, Color>("functions", Color(1, 0.9, 0.9)));
- colors.push_back(Pair<String, Color>("data", Color(0.9, 1.0, 0.9)));
- colors.push_back(Pair<String, Color>("operators", Color(0.9, 0.9, 1.0)));
- colors.push_back(Pair<String, Color>("flow_control", Color(1.0, 1.0, 1.0)));
- colors.push_back(Pair<String, Color>("custom", Color(0.8, 1.0, 1.0)));
- colors.push_back(Pair<String, Color>("constants", Color(1.0, 0.8, 1.0)));
+ if (dark_theme) {
+ colors.push_back(Pair<String, Color>("flow_control", Color::html("#f4f4f4")));
+ colors.push_back(Pair<String, Color>("functions", Color::html("#f58581")));
+ colors.push_back(Pair<String, Color>("data", Color::html("#80f6cf")));
+ colors.push_back(Pair<String, Color>("operators", Color::html("#ab97df")));
+ colors.push_back(Pair<String, Color>("custom", Color::html("#80bbf6")));
+ colors.push_back(Pair<String, Color>("constants", Color::html("#f680b0")));
+ } else {
+ colors.push_back(Pair<String, Color>("flow_control", Color::html("#424242")));
+ colors.push_back(Pair<String, Color>("functions", Color::html("#f26661")));
+ colors.push_back(Pair<String, Color>("data", Color::html("#13bb83")));
+ colors.push_back(Pair<String, Color>("operators", Color::html("#8265d0")));
+ colors.push_back(Pair<String, Color>("custom", Color::html("#4ea0f2")));
+ colors.push_back(Pair<String, Color>("constants", Color::html("#f02f7d")));
+ }
for (List<Pair<String, Color> >::Element *E = colors.front(); E; E = E->next()) {
- print_line(E->get().first);
- Ref<StyleBoxFlat> sb = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox("frame", "GraphNode");
- if (sb != NULL) {
+ Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
+ if (!sb.is_null()) {
Ref<StyleBoxFlat> frame_style = sb->duplicate();
Color c = sb->get_border_color(MARGIN_TOP);
Color cn = E->get().second;
@@ -2880,7 +2939,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
if (node.is_valid()) {
clipboard->nodes[id] = node->duplicate();
- clipboard->nodes_positions[id] = script->get_node_pos(edited_func, id);
+ clipboard->nodes_positions[id] = script->get_node_position(edited_func, id);
}
}
}
@@ -2940,7 +2999,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
List<int> nodes;
script->get_node_list(edited_func, &nodes);
for (List<int>::Element *E = nodes.front(); E; E = E->next()) {
- Vector2 pos = script->get_node_pos(edited_func, E->get()).snapped(Vector2(2, 2));
+ Vector2 pos = script->get_node_position(edited_func, E->get()).snapped(Vector2(2, 2));
existing_positions.insert(pos);
}
}
@@ -3054,7 +3113,7 @@ void VisualScriptEditor::_member_option(int p_option) {
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_pos(name, E->get()));
+ 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;
@@ -3252,8 +3311,7 @@ VisualScriptEditor::VisualScriptEditor() {
graph = memnew(GraphEdit);
add_child(graph);
- graph->set_area_as_parent_rect();
- graph->set_h_size_flags(SIZE_EXPAND_FILL);
+ graph->set_anchors_and_margins_preset(Control::PRESET_WIDE);
graph->connect("node_selected", this, "_node_selected");
graph->connect("_begin_node_move", this, "_begin_node_move");
graph->connect("_end_node_move", this, "_end_node_move");
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index eae866d167..897e910f20 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -1023,7 +1023,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
case TK_OP_OR: op = Variant::OP_OR; break;
case TK_OP_NOT: op = Variant::OP_NOT; break;
case TK_OP_ADD: op = Variant::OP_ADD; break;
- case TK_OP_SUB: op = Variant::OP_SUBSTRACT; break;
+ case TK_OP_SUB: op = Variant::OP_SUBTRACT; break;
case TK_OP_MUL: op = Variant::OP_MULTIPLY; break;
case TK_OP_DIV: op = Variant::OP_DIVIDE; break;
case TK_OP_MOD: op = Variant::OP_MODULE; break;
@@ -1085,7 +1085,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
case Variant::OP_MODULE: priority = 2; break;
case Variant::OP_ADD: priority = 3; break;
- case Variant::OP_SUBSTRACT: priority = 3; break;
+ case Variant::OP_SUBTRACT: priority = 3; break;
case Variant::OP_SHIFT_LEFT: priority = 4; break;
case Variant::OP_SHIFT_RIGHT: priority = 4; break;
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 267946750f..8d73de9889 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -42,7 +42,7 @@
int VisualScriptFunctionCall::get_output_sequence_port_count() const {
- if (method_cache.flags & METHOD_FLAG_CONST || call_mode == CALL_MODE_BASIC_TYPE)
+ if (method_cache.flags & METHOD_FLAG_CONST || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_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 {
- if (method_cache.flags & METHOD_FLAG_CONST || call_mode == CALL_MODE_BASIC_TYPE)
+ if (method_cache.flags & METHOD_FLAG_CONST || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function)))
return false;
else
return true;
@@ -763,7 +763,7 @@ public:
NodePath node_path;
int input_args;
bool validate;
- bool returns;
+ int returns;
VisualScriptFunctionCall::RPCCallMode rpc_mode;
StringName function;
StringName singleton;
@@ -856,7 +856,13 @@ public:
}
} else if (returns) {
if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
- *p_outputs[1] = v.call(function, p_inputs + 1, input_args, r_error);
+ if (returns >= 2) {
+ *p_outputs[1] = v.call(function, p_inputs + 1, input_args, r_error);
+ } else {
+ r_error.error = Variant::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);
}
@@ -1546,7 +1552,7 @@ public:
value = Variant::evaluate(Variant::OP_ADD, value, p_argument);
} break;
case VisualScriptPropertySet::ASSIGN_OP_SUB: {
- value = Variant::evaluate(Variant::OP_SUBSTRACT, value, p_argument);
+ value = Variant::evaluate(Variant::OP_SUBTRACT, value, p_argument);
} break;
case VisualScriptPropertySet::ASSIGN_OP_MUL: {
value = Variant::evaluate(Variant::OP_MULTIPLY, value, p_argument);
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index b617c11bab..d3cd839cf3 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -532,6 +532,7 @@ String VisualScriptOperator::get_text() const {
L"A or B", //OP_OR,
L"A xor B", //OP_XOR,
L"not A", //OP_NOT,
+ L"A in B", //OP_IN,
};
return op_names[op];
@@ -1109,7 +1110,7 @@ void VisualScriptConstant::_bind_methods() {
}
ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type");
- ADD_PROPERTY(PropertyInfo(Variant::NIL, "value"), "set_constant_value", "get_constant_value");
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_constant_value", "get_constant_value");
}
class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance {
@@ -1598,7 +1599,7 @@ VisualScriptNodeInstance *VisualScriptClassConstant::instance(VisualScriptInstan
void VisualScriptClassConstant::_validate_property(PropertyInfo &property) const {
- if (property.name == "constant/constant") {
+ if (property.name == "constant") {
List<String> constants;
ClassDB::get_integer_constant_list(base_type, &constants, true);
@@ -1727,7 +1728,7 @@ VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instance(VisualScriptIn
void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) const {
- if (property.name == "constant/constant") {
+ if (property.name == "constant") {
List<StringName> constants;
Variant::get_numeric_constants_for_type(type, &constants);
@@ -2689,7 +2690,7 @@ VisualScriptNodeInstance *VisualScriptCustomNode::instance(VisualScriptInstance
}
void VisualScriptCustomNode::_script_changed() {
- ports_changed_notify();
+ call_deferred("ports_changed_notify");
}
void VisualScriptCustomNode::_bind_methods() {
@@ -3762,7 +3763,7 @@ void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("operators/compare/greater_equal", create_op_node<Variant::OP_GREATER_EQUAL>);
//mathematic
VisualScriptLanguage::singleton->add_register_func("operators/math/add", create_op_node<Variant::OP_ADD>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/subtract", create_op_node<Variant::OP_SUBSTRACT>);
+ VisualScriptLanguage::singleton->add_register_func("operators/math/subtract", create_op_node<Variant::OP_SUBTRACT>);
VisualScriptLanguage::singleton->add_register_func("operators/math/multiply", create_op_node<Variant::OP_MULTIPLY>);
VisualScriptLanguage::singleton->add_register_func("operators/math/divide", create_op_node<Variant::OP_DIVIDE>);
VisualScriptLanguage::singleton->add_register_func("operators/math/negate", create_op_node<Variant::OP_NEGATE>);
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index b6d4021ca3..3c9076246d 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -82,7 +82,7 @@ String VisualScriptYield::get_text() const {
switch (yield_mode) {
case YIELD_RETURN: return ""; break;
case YIELD_FRAME: return "Next Frame"; break;
- case YIELD_FIXED_FRAME: return "Next Fixed Frame"; break;
+ case YIELD_PHYSICS_FRAME: return "Next Physics Frame"; break;
case YIELD_WAIT: return rtos(wait_time) + " sec(s)"; break;
}
@@ -122,7 +122,7 @@ public:
ret = STEP_EXIT_FUNCTION_BIT;
break; //return the yield
case VisualScriptYield::YIELD_FRAME: state->connect_to_signal(tree, "idle_frame", Array()); break;
- case VisualScriptYield::YIELD_FIXED_FRAME: state->connect_to_signal(tree, "fixed_frame", Array()); break;
+ case VisualScriptYield::YIELD_PHYSICS_FRAME: state->connect_to_signal(tree, "physics_frame", Array()); break;
case VisualScriptYield::YIELD_WAIT: state->connect_to_signal(tree->create_timer(wait_time).ptr(), "timeout", Array()); break;
}
@@ -186,11 +186,11 @@ void VisualScriptYield::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_wait_time", "sec"), &VisualScriptYield::set_wait_time);
ClassDB::bind_method(D_METHOD("get_wait_time"), &VisualScriptYield::get_wait_time);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,FixedFrame,Time", PROPERTY_USAGE_NOEDITOR), "set_yield_mode", "get_yield_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,Physics Frame,Time", PROPERTY_USAGE_NOEDITOR), "set_yield_mode", "get_yield_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "wait_time"), "set_wait_time", "get_wait_time");
BIND_ENUM_CONSTANT(YIELD_FRAME);
- BIND_ENUM_CONSTANT(YIELD_FIXED_FRAME);
+ BIND_ENUM_CONSTANT(YIELD_PHYSICS_FRAME);
BIND_ENUM_CONSTANT(YIELD_WAIT);
}
@@ -597,7 +597,7 @@ static Ref<VisualScriptNode> create_yield_signal_node(const String &p_name) {
void register_visual_script_yield_nodes() {
VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_frame", create_yield_node<VisualScriptYield::YIELD_FRAME>);
- VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_fixed_frame", create_yield_node<VisualScriptYield::YIELD_FIXED_FRAME>);
+ VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_physics_frame", create_yield_node<VisualScriptYield::YIELD_PHYSICS_FRAME>);
VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_time", create_yield_node<VisualScriptYield::YIELD_WAIT>);
VisualScriptLanguage::singleton->add_register_func("functions/yield", create_yield_node<VisualScriptYield::YIELD_RETURN>);
diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h
index d074962471..4a595a875a 100644
--- a/modules/visual_script/visual_script_yield_nodes.h
+++ b/modules/visual_script/visual_script_yield_nodes.h
@@ -39,7 +39,7 @@ public:
enum YieldMode {
YIELD_RETURN,
YIELD_FRAME,
- YIELD_FIXED_FRAME,
+ YIELD_PHYSICS_FRAME,
YIELD_WAIT
};
diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub
index d3e4f7e15a..9d2d0feb92 100644
--- a/modules/vorbis/SCsub
+++ b/modules/vorbis/SCsub
@@ -6,7 +6,7 @@ Import('env_modules')
env_vorbis = env_modules.Clone()
# Thirdparty source files
-if (env['builtin_libvorbis'] != 'no'):
+if env['builtin_libvorbis']:
thirdparty_dir = "#thirdparty/libvorbis/"
thirdparty_sources = [
#"analysis.c",
@@ -42,7 +42,7 @@ if (env['builtin_libvorbis'] != 'no'):
env_vorbis.Append(CPPPATH=[thirdparty_dir])
# also requires libogg
- if (env['builtin_libogg'] != 'no'):
+ if env['builtin_libogg']:
env_vorbis.Append(CPPPATH=["#thirdparty/libogg"])
# Godot source files
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
index 6389c286c2..6235799fc2 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -58,7 +58,7 @@ int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f, ogg_int64_t offs, int
fa->seek(offs);
} else if (whence == SEEK_CUR) {
- fa->seek(fa->get_pos() + offs);
+ fa->seek(fa->get_position() + offs);
} else if (whence == SEEK_END) {
fa->seek_end(offs);
@@ -89,10 +89,10 @@ long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) {
//printf("close %p\n",_f);
FileAccess *fa = (FileAccess *)_f;
- return fa->get_pos();
+ return fa->get_position();
}
-int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_bufer, int p_frames) {
+int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_buffer, int p_frames) {
if (!playing)
return 0;
@@ -109,9 +109,9 @@ int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_bufer, int p_frames) {
//printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t));
#ifdef BIG_ENDIAN_ENABLED
- long ret = ov_read(&vf, (char *)p_bufer, todo * stream_channels * sizeof(int16_t), 1, 2, 1, &current_section);
+ long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 1, 2, 1, &current_section);
#else
- long ret = ov_read(&vf, (char *)p_bufer, todo * stream_channels * sizeof(int16_t), 0, 2, 1, &current_section);
+ long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 0, 2, 1, &current_section);
#endif
if (ret < 0) {
@@ -162,7 +162,7 @@ int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_bufer, int p_frames) {
frames_mixed += ret;
- p_bufer += ret * stream_channels;
+ p_buffer += ret * stream_channels;
p_frames -= ret;
}
@@ -180,7 +180,7 @@ void AudioStreamPlaybackOGGVorbis::play(float p_from) {
frames_mixed = 0;
playing = true;
if (p_from > 0) {
- seek_pos(p_from);
+ seek(p_from);
}
}
@@ -203,7 +203,7 @@ void AudioStreamPlaybackOGGVorbis::stop() {
//_clear();
}
-float AudioStreamPlaybackOGGVorbis::get_pos() const {
+float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
int32_t frames = int32_t(frames_mixed);
if (frames < 0)
@@ -211,7 +211,7 @@ float AudioStreamPlaybackOGGVorbis::get_pos() const {
return double(frames) / stream_srate;
}
-void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) {
+void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
if (!playing)
return;
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h
index 03b3726b52..79eadec56e 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/vorbis/audio_stream_ogg_vorbis.h
@@ -96,14 +96,14 @@ public:
virtual int get_loop_count() const;
- virtual float get_pos() const;
- virtual void seek_pos(float p_time);
+ virtual float get_playback_position() const;
+ virtual void seek(float p_time);
virtual int get_channels() const { return stream_channels; }
virtual int get_mix_rate() const { return stream_srate; }
virtual int get_minimum_buffer_size() const { return 0; }
- virtual int mix(int16_t *p_bufer, int p_frames);
+ virtual int mix(int16_t *p_buffer, int p_frames);
AudioStreamPlaybackOGGVorbis();
~AudioStreamPlaybackOGGVorbis();
diff --git a/modules/webm/SCsub b/modules/webm/SCsub
index 889f5e83aa..2f1a28a54c 100644
--- a/modules/webm/SCsub
+++ b/modules/webm/SCsub
@@ -19,14 +19,14 @@ env_webm.add_source_files(env.modules_sources, thirdparty_libsimplewebm_sources)
env_webm.Append(CPPPATH=[thirdparty_libsimplewebm_dir, thirdparty_libsimplewebm_dir + "libwebm/"])
# also requires libogg, libvorbis and libopus
-if (env['builtin_libogg'] != 'no'):
+if env['builtin_libogg']:
env_webm.Append(CPPPATH=["#thirdparty/libogg"])
-if (env['builtin_libvorbis'] != 'no'):
+if env['builtin_libvorbis']:
env_webm.Append(CPPPATH=["#thirdparty/libvorbis"])
-if (env['builtin_opus'] != 'no'):
+if env['builtin_opus']:
env_webm.Append(CPPPATH=["#thirdparty/opus"])
-if (env['builtin_libvpx'] != 'no'):
+if env['builtin_libvpx']:
Export('env_webm')
SConscript("libvpx/SCsub")
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index 0ee2ed45b8..fd8d762a5e 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -265,7 +265,7 @@ if env["platform"] == 'uwp':
else:
import platform
is_x11_or_server_arm = ((env["platform"] == 'x11' or env["platform"] == 'server') and platform.machine().startswith('arm'))
- is_ios_x86 = (env["platform"] == 'iphone' and env["ios_sim"] == "yes")
+ is_ios_x86 = (env["platform"] == 'iphone' and env["ios_sim"])
is_android_x86 = (env["platform"] == 'android' and env["android_arch"] == 'x86')
if is_android_x86:
cpu_bits = '32'
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 0178ebab84..2ec6b27471 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -59,7 +59,7 @@ public:
if (file) {
- if (file->get_pos() != (size_t)pos)
+ if (file->get_position() != (size_t)pos)
file->seek(pos);
if (file->get_buffer(buf, len) == len)
return 0;
@@ -204,11 +204,11 @@ float VideoStreamPlaybackWebm::get_length() const {
return 0.0f;
}
-float VideoStreamPlaybackWebm::get_pos() const {
+float VideoStreamPlaybackWebm::get_playback_position() const {
return video_pos;
}
-void VideoStreamPlaybackWebm::seek_pos(float p_time) {
+void VideoStreamPlaybackWebm::seek(float p_time) {
//Not implemented
}
diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h
index 9a331849be..fc0720967a 100644
--- a/modules/webm/video_stream_webm.h
+++ b/modules/webm/video_stream_webm.h
@@ -81,8 +81,8 @@ public:
virtual float get_length() const;
- virtual float get_pos() const;
- virtual void seek_pos(float p_time);
+ virtual float get_playback_position() const;
+ virtual void seek(float p_time);
virtual void set_audio_track(int p_idx);
diff --git a/modules/webp/SCsub b/modules/webp/SCsub
index aa3486a2c5..f9295fed47 100644
--- a/modules/webp/SCsub
+++ b/modules/webp/SCsub
@@ -6,7 +6,7 @@ Import('env_modules')
env_webp = env_modules.Clone()
# Thirdparty source files
-if (env['builtin_libwebp'] != 'no'):
+if env['builtin_libwebp']:
thirdparty_dir = "#thirdparty/libwebp/"
thirdparty_sources = [
"dec/alpha_dec.c",