summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/area_bullet.cpp4
-rw-r--r--modules/bullet/bullet_physics_server.cpp46
-rw-r--r--modules/bullet/bullet_physics_server.h9
-rw-r--r--modules/bullet/cone_twist_joint_bullet.cpp20
-rw-r--r--modules/bullet/cone_twist_joint_bullet.h8
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.cpp53
-rw-r--r--modules/bullet/generic_6dof_joint_bullet.h4
-rw-r--r--modules/bullet/godot_result_callbacks.cpp68
-rw-r--r--modules/bullet/godot_result_callbacks.h44
-rw-r--r--modules/bullet/hinge_joint_bullet.cpp6
-rw-r--r--modules/bullet/rigid_body_bullet.cpp18
-rw-r--r--modules/bullet/rigid_body_bullet.h9
-rw-r--r--modules/bullet/shape_bullet.cpp45
-rw-r--r--modules/bullet/shape_bullet.h24
-rw-r--r--modules/bullet/soft_body_bullet.cpp2
-rw-r--r--modules/bullet/space_bullet.cpp187
-rw-r--r--modules/bullet/space_bullet.h17
-rw-r--r--modules/csg/csg.h2
-rw-r--r--modules/csg/csg_gizmos.cpp77
-rw-r--r--modules/csg/csg_gizmos.h24
-rw-r--r--modules/csg/csg_shape.cpp4
-rw-r--r--modules/cvtt/SCsub21
-rw-r--r--modules/cvtt/config.py5
-rw-r--r--modules/cvtt/image_compress_cvtt.cpp394
-rw-r--r--modules/cvtt/image_compress_cvtt.h39
-rw-r--r--modules/cvtt/register_types.cpp45
-rw-r--r--modules/cvtt/register_types.h34
-rw-r--r--modules/dds/texture_loader_dds.cpp2
-rw-r--r--modules/etc/image_etc.cpp33
-rw-r--r--modules/gdnative/doc_classes/NativeScript.xml4
-rw-r--r--modules/gdnative/gdnative/pool_arrays.cpp2
-rw-r--r--modules/gdnative/gdnative/rect2.cpp2
-rw-r--r--modules/gdnative/gdnative/transform2d.cpp2
-rw-r--r--modules/gdnative/gdnative/vector2.cpp2
-rw-r--r--modules/gdnative/gdnative_api.json8
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h3
-rw-r--r--modules/gdnative/nativescript/godot_nativescript.cpp4
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp152
-rw-r--r--modules/gdnative/nativescript/nativescript.h31
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.cpp2
-rw-r--r--modules/gdnative/pluginscript/pluginscript_language.h2
-rw-r--r--modules/gdscript/gdscript.cpp254
-rw-r--r--modules/gdscript/gdscript.h48
-rw-r--r--modules/gdscript/gdscript_compiler.cpp10
-rw-r--r--modules/gdscript/gdscript_editor.cpp24
-rw-r--r--modules/gdscript/gdscript_functions.cpp6
-rw-r--r--modules/gdscript/gdscript_parser.cpp479
-rw-r--r--modules/gdscript/gdscript_parser.h25
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp22
-rw-r--r--modules/gdscript/gdscript_tokenizer.h28
-rw-r--r--modules/gridmap/grid_map.cpp78
-rw-r--r--modules/gridmap/grid_map.h7
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp147
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h16
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp105
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h2
-rw-r--r--modules/mono/SCsub25
-rw-r--r--modules/mono/config.py6
-rw-r--r--modules/mono/csharp_script.cpp71
-rw-r--r--modules/mono/csharp_script.h3
-rw-r--r--modules/mono/editor/bindings_generator.cpp9
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp10
-rw-r--r--modules/mono/glue/collections_glue.cpp4
-rw-r--r--modules/mono/glue/cs_files/AABB.cs200
-rw-r--r--modules/mono/glue/cs_files/Array.cs5
-rw-r--r--modules/mono/glue/cs_files/Attributes/ExportAttribute.cs17
-rw-r--r--modules/mono/glue/cs_files/Attributes/GodotMethodAttribute.cs (renamed from modules/mono/glue/cs_files/GodotMethodAttribute.cs)0
-rw-r--r--modules/mono/glue/cs_files/Attributes/RPCAttributes.cs (renamed from modules/mono/glue/cs_files/RPCAttributes.cs)0
-rw-r--r--modules/mono/glue/cs_files/Attributes/SignalAttribute.cs (renamed from modules/mono/glue/cs_files/SignalAttribute.cs)0
-rw-r--r--modules/mono/glue/cs_files/Attributes/ToolAttribute.cs7
-rw-r--r--modules/mono/glue/cs_files/Color.cs5
-rw-r--r--modules/mono/glue/cs_files/Dictionary.cs5
-rw-r--r--modules/mono/glue/cs_files/ExportAttribute.cs17
-rw-r--r--modules/mono/glue/cs_files/Extensions/NodeExtensions.cs (renamed from modules/mono/glue/cs_files/NodeExtensions.cs)0
-rw-r--r--modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs17
-rw-r--r--modules/mono/glue/cs_files/Extensions/ResourceLoaderExtensions.cs10
-rw-r--r--modules/mono/glue/cs_files/GD.cs10
-rw-r--r--modules/mono/glue/cs_files/IAwaiter.cs18
-rw-r--r--modules/mono/glue/cs_files/Interfaces/IAwaitable.cs (renamed from modules/mono/glue/cs_files/IAwaitable.cs)0
-rw-r--r--modules/mono/glue/cs_files/Interfaces/IAwaiter.cs18
-rw-r--r--modules/mono/glue/cs_files/Plane.cs9
-rw-r--r--modules/mono/glue/cs_files/Rect2.cs122
-rw-r--r--modules/mono/glue/cs_files/StringExtensions.cs14
-rw-r--r--modules/mono/glue/cs_files/ToolAttribute.cs7
-rw-r--r--modules/mono/glue/cs_files/Transform.cs13
-rw-r--r--modules/mono/glue/cs_files/Transform2D.cs21
-rwxr-xr-xmodules/mono/glue/cs_files/VERSION.txt1
-rw-r--r--modules/mono/glue/cs_files/Vector2.cs44
-rw-r--r--modules/mono/glue/cs_files/Vector3.cs46
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp46
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp76
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h3
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp3
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp4
-rw-r--r--modules/mono/utils/thread_local.cpp4
-rw-r--r--modules/mono/utils/thread_local.h3
-rw-r--r--modules/pvr/texture_loader_pvr.cpp16
-rw-r--r--modules/squish/image_compress_squish.cpp47
-rw-r--r--modules/squish/image_compress_squish.h2
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp2
-rw-r--r--modules/theora/video_stream_theora.cpp10
-rw-r--r--modules/theora/video_stream_theora.h1
-rw-r--r--modules/visual_script/visual_script.cpp2
-rw-r--r--modules/visual_script/visual_script.h2
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp5
-rw-r--r--modules/visual_script/visual_script_editor.cpp4
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp1
-rw-r--r--modules/visual_script/visual_script_nodes.cpp6
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp1
-rw-r--r--modules/webm/video_stream_webm.h1
-rw-r--r--modules/websocket/SCsub165
-rw-r--r--modules/websocket/lws_client.cpp9
-rw-r--r--modules/websocket/lws_peer.cpp71
-rw-r--r--modules/websocket/lws_peer.h13
-rw-r--r--modules/websocket/lws_server.cpp9
115 files changed, 2866 insertions, 1083 deletions
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
index b004641838..3668088590 100644
--- a/modules/bullet/area_bullet.cpp
+++ b/modules/bullet/area_bullet.cpp
@@ -236,7 +236,7 @@ void AreaBullet::set_param(PhysicsServer::AreaParameter p_param, const Variant &
set_spOv_gravityPointAttenuation(p_value);
break;
default:
- print_line("The Bullet areas doesn't suppot this param: " + itos(p_param));
+ WARN_PRINTS("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));
}
}
@@ -259,7 +259,7 @@ Variant AreaBullet::get_param(PhysicsServer::AreaParameter p_param) const {
case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:
return spOv_gravityPointAttenuation;
default:
- print_line("The Bullet areas doesn't suppot this param: " + itos(p_param));
+ WARN_PRINTS("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));
return Variant();
}
}
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 9263a9ba6d..dbd27a3564 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -163,6 +163,18 @@ Variant BulletPhysicsServer::shape_get_data(RID p_shape) const {
return shape->get_data();
}
+void BulletPhysicsServer::shape_set_margin(RID p_shape, real_t p_margin) {
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND(!shape);
+ shape->set_margin(p_margin);
+}
+
+real_t BulletPhysicsServer::shape_get_margin(RID p_shape) const {
+ ShapeBullet *shape = shape_owner.get(p_shape);
+ ERR_FAIL_COND_V(!shape, 0.0);
+ return shape->get_margin();
+}
+
real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const {
//WARN_PRINT("Bias not supported by Bullet physics engine");
return 0.;
@@ -644,20 +656,6 @@ float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) con
return body->get_param(p_param);
}
-void BulletPhysicsServer::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) {
- RigidBodyBullet *body = rigid_body_owner.get(p_body);
- ERR_FAIL_COND(!body);
-
- body->set_combine_mode(p_param, p_mode);
-}
-
-PhysicsServer::CombineMode BulletPhysicsServer::body_get_combine_mode(RID p_body, BodyParameter p_param) const {
- RigidBodyBullet *body = rigid_body_owner.get(p_body);
- ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT);
-
- return body->get_combine_mode(p_param);
-}
-
void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
RigidBodyBullet *body = rigid_body_owner.get(p_body);
ERR_FAIL_COND(!body);
@@ -875,12 +873,20 @@ PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) {
return BulletPhysicsDirectBodyState::get_singleton(body);
}
-bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result) {
+bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
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_infinite_inertia, r_result);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
+}
+
+int BulletPhysicsServer::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) {
+ RigidBodyBullet *body = rigid_body_owner.get(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+ ERR_FAIL_COND_V(!body->get_space(), 0);
+
+ return body->get_space()->test_ray_separation(body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin);
}
RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) {
@@ -995,11 +1001,13 @@ void BulletPhysicsServer::soft_body_get_collision_exceptions(RID p_body, List<RI
}
void BulletPhysicsServer::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
- print_line("TODO MUST BE IMPLEMENTED");
+ // FIXME: Must be implemented.
+ WARN_PRINT("soft_body_state is not implemented yet in Bullet backend.");
}
Variant BulletPhysicsServer::soft_body_get_state(RID p_body, BodyState p_state) const {
- print_line("TODO MUST BE IMPLEMENTED");
+ // FIXME: Must be implemented.
+ WARN_PRINT("soft_body_state is not implemented yet in Bullet backend.");
return Variant();
}
@@ -1433,7 +1441,7 @@ RID BulletPhysicsServer::joint_create_generic_6dof(RID p_body_A, const Transform
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));
+ JointBullet *joint = bulletnew(Generic6DOFJointBullet(body_A, body_B, p_local_frame_A, p_local_frame_B));
AddJointToSpace(body_A, joint);
CreateThenReturnRID(joint_owner, joint);
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 2c5b7e51cf..e9c568d605 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -99,6 +99,9 @@ public:
virtual ShapeType shape_get_type(RID p_shape) const;
virtual Variant shape_get_data(RID p_shape) const;
+ virtual void shape_set_margin(RID p_shape, real_t p_margin);
+ virtual real_t shape_get_margin(RID p_shape) const;
+
/// Not supported
virtual void shape_set_custom_solver_bias(RID p_shape, real_t p_bias);
/// Not supported
@@ -213,9 +216,6 @@ public:
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_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode);
- virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const;
-
virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
@@ -261,7 +261,8 @@ public:
// 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, bool p_infinite_inertia, MotionResult *r_result = NULL);
+ virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true);
+ virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001);
/* SOFT BODY API */
diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp
index 472ad3b52c..6b5438c60f 100644
--- a/modules/bullet/cone_twist_joint_bullet.cpp
+++ b/modules/bullet/cone_twist_joint_bullet.cpp
@@ -64,26 +64,6 @@ ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet
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:
diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h
index bd6eb49196..d6040fd6ec 100644
--- a/modules/bullet/cone_twist_joint_bullet.h
+++ b/modules/bullet/cone_twist_joint_bullet.h
@@ -47,14 +47,6 @@ public:
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;
};
diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp
index adfad7803f..6275a0d2ed 100644
--- a/modules/bullet/generic_6dof_joint_bullet.cpp
+++ b/modules/bullet/generic_6dof_joint_bullet.cpp
@@ -34,13 +34,13 @@
#include "bullet_utilities.h"
#include "rigid_body_bullet.h"
-#include <BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h>
+#include <BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h>
/**
@author AndreaCatania
*/
-Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) :
+Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) :
JointBullet() {
Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale()));
@@ -58,9 +58,9 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu
btTransform btFrameB;
G_TO_B(scaled_BFrame, btFrameB);
- sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB, useLinearReferenceFrameA));
+ sixDOFConstraint = bulletnew(btGeneric6DofSpring2Constraint(*rbA->get_bt_rigid_body(), *rbB->get_bt_rigid_body(), btFrameA, btFrameB));
} else {
- sixDOFConstraint = bulletnew(btGeneric6DofConstraint(*rbA->get_bt_rigid_body(), btFrameA, useLinearReferenceFrameA));
+ sixDOFConstraint = bulletnew(btGeneric6DofSpring2Constraint(*rbA->get_bt_rigid_body(), btFrameA));
}
setup(sixDOFConstraint);
@@ -123,20 +123,11 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO
switch (p_param) {
case PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT:
limits_lower[0][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter
+ set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter
break;
case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
limits_upper[0][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter
- 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;
+ set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT]); // Reload bullet parameter
break;
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY:
sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis] = p_value;
@@ -146,23 +137,11 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO
break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT:
limits_lower[1][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter
+ set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
limits_upper[1][p_axis] = p_value;
- set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, flags[p_axis][p_param]); // Reload bullet parameter
- 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;
+ set_flag(p_axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, flags[p_axis][PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT]); // Reload bullet parameter
break;
case PhysicsServer::G6DOF_JOINT_ANGULAR_ERP:
sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_stopERP = p_value;
@@ -171,7 +150,7 @@ void Generic6DOFJointBullet::set_param(Vector3::Axis p_axis, PhysicsServer::G6DO
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;
+ sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce = p_value;
break;
default:
WARN_PRINT("This parameter is not supported");
@@ -185,12 +164,6 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6
return limits_lower[0][p_axis];
case PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT:
return limits_upper[0][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_LINEAR_MOTOR_TARGET_VELOCITY:
return sixDOFConstraint->getTranslationalLimitMotor()->m_targetVelocity.m_floats[p_axis];
case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT:
@@ -199,20 +172,14 @@ real_t Generic6DOFJointBullet::get_param(Vector3::Axis p_axis, PhysicsServer::G6
return limits_lower[1][p_axis];
case PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT:
return limits_upper[1][p_axis];
- 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;
+ return sixDOFConstraint->getRotationalLimitMotor(p_axis)->m_maxMotorForce;
default:
WARN_PRINT("This parameter is not supported");
return 0.;
diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h
index ad06582eac..176127ed6c 100644
--- a/modules/bullet/generic_6dof_joint_bullet.h
+++ b/modules/bullet/generic_6dof_joint_bullet.h
@@ -40,7 +40,7 @@
class RigidBodyBullet;
class Generic6DOFJointBullet : public JointBullet {
- class btGeneric6DofConstraint *sixDOFConstraint;
+ class btGeneric6DofSpring2Constraint *sixDOFConstraint;
// First is linear second is angular
Vector3 limits_lower[2];
@@ -48,7 +48,7 @@ class Generic6DOFJointBullet : public JointBullet {
bool flags[3][PhysicsServer::G6DOF_JOINT_FLAG_MAX];
public:
- Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA);
+ Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB);
virtual PhysicsServer::JointType get_type() const { return PhysicsServer::JOINT_6DOF; }
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 197550d686..534034d707 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -30,6 +30,7 @@
#include "godot_result_callbacks.h"
+#include "area_bullet.h"
#include "bullet_types_converter.h"
#include "collision_object_bullet.h"
#include "rigid_body_bullet.h"
@@ -51,11 +52,23 @@ bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) co
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())) {
+
+ if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
+ if (!collide_with_areas)
+ return false;
+ } else {
+ if (!collide_with_bodies)
+ return false;
+ }
+
+ if (m_pickRay && !gObj->is_ray_pickable()) {
+ return false;
+ }
+
+ if (m_exclude->has(gObj->get_self())) {
return false;
}
+
return true;
} else {
return false;
@@ -124,6 +137,15 @@ bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0)
if (needs) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+
+ if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
+ if (!collide_with_areas)
+ return false;
+ } else {
+ if (!collide_with_bodies)
+ return false;
+ }
+
if (m_exclude->has(gObj->get_self())) {
return false;
}
@@ -144,6 +166,15 @@ bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) co
if (needs) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+
+ if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
+ if (!collide_with_areas)
+ return false;
+ } else {
+ if (!collide_with_bodies)
+ return false;
+ }
+
if (m_exclude->has(gObj->get_self())) {
return false;
}
@@ -189,6 +220,15 @@ bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *pr
if (needs) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+
+ if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
+ if (!collide_with_areas)
+ return false;
+ } else {
+ if (!collide_with_bodies)
+ return false;
+ }
+
if (m_exclude->has(gObj->get_self())) {
return false;
}
@@ -218,6 +258,15 @@ bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy
if (needs) {
btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject);
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer());
+
+ if (CollisionObjectBullet::TYPE_AREA == gObj->getType()) {
+ if (!collide_with_areas)
+ return false;
+ } else {
+ if (!collide_with_bodies)
+ return false;
+ }
+
if (m_exclude->has(gObj->get_self())) {
return false;
}
@@ -260,10 +309,19 @@ void GodotDeepPenetrationContactResultCallback::addContactPoint(const btVector3
if (m_penetration_distance > depth) { // Has penetration?
- bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject();
+ const bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject();
m_penetration_distance = depth;
m_other_compound_shape_index = isSwapped ? m_index0 : m_index1;
- m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld;
m_pointWorld = isSwapped ? (pointInWorldOnB + (normalOnBInWorld * depth)) : pointInWorldOnB;
+
+ const btCollisionObjectWrapper *bw0 = m_body0Wrap;
+ if (isSwapped)
+ bw0 = m_body1Wrap;
+
+ if (bw0->getCollisionShape()->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) {
+ m_pointNormalWorld = bw0->m_worldTransform.getBasis().transpose() * btVector3(0, 0, 1);
+ } else {
+ m_pointNormalWorld = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld;
+ }
}
}
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
index 363051f24c..3948f43c00 100644
--- a/modules/bullet/godot_result_callbacks.h
+++ b/modules/bullet/godot_result_callbacks.h
@@ -56,12 +56,17 @@ struct GodotClosestRayResultCallback : public btCollisionWorld::ClosestRayResult
bool m_pickRay;
int m_shapeId;
+ bool collide_with_bodies;
+ bool collide_with_areas;
+
public:
- GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude) :
+ GodotClosestRayResultCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld),
m_exclude(p_exclude),
m_pickRay(false),
- m_shapeId(0) {}
+ m_shapeId(0),
+ collide_with_bodies(p_collide_with_bodies),
+ collide_with_areas(p_collide_with_areas) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
@@ -108,9 +113,14 @@ public:
const Set<RID> *m_exclude;
int m_shapeId;
- GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude) :
+ bool collide_with_bodies;
+ bool collide_with_areas;
+
+ GodotClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld),
- m_exclude(p_exclude) {}
+ m_exclude(p_exclude),
+ collide_with_bodies(p_collide_with_bodies),
+ collide_with_areas(p_collide_with_areas) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
@@ -125,12 +135,17 @@ public:
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) :
+ bool collide_with_bodies;
+ bool collide_with_areas;
+
+ GodotAllContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeResult *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
m_self_object(p_self_object),
m_results(p_results),
m_exclude(p_exclude),
m_resultMax(p_resultMax),
- m_count(0) {}
+ m_count(0),
+ collide_with_bodies(p_collide_with_bodies),
+ collide_with_areas(p_collide_with_areas) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
@@ -146,12 +161,17 @@ public:
int m_count;
const Set<RID> *m_exclude;
- GodotContactPairContactResultCallback(btCollisionObject *p_self_object, Vector3 *p_results, int p_resultMax, const Set<RID> *p_exclude) :
+ bool collide_with_bodies;
+ bool collide_with_areas;
+
+ GodotContactPairContactResultCallback(btCollisionObject *p_self_object, Vector3 *p_results, int p_resultMax, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
m_self_object(p_self_object),
m_results(p_results),
m_exclude(p_exclude),
m_resultMax(p_resultMax),
- m_count(0) {}
+ m_count(0),
+ collide_with_bodies(p_collide_with_bodies),
+ collide_with_areas(p_collide_with_areas) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
@@ -167,13 +187,17 @@ public:
const btCollisionObject *m_rest_info_collision_object;
btVector3 m_rest_info_bt_point;
const Set<RID> *m_exclude;
+ bool collide_with_bodies;
+ bool collide_with_areas;
- GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeRestInfo *p_result, const Set<RID> *p_exclude) :
+ GodotRestInfoContactResultCallback(btCollisionObject *p_self_object, PhysicsDirectSpaceState::ShapeRestInfo *p_result, const Set<RID> *p_exclude, bool p_collide_with_bodies, bool p_collide_with_areas) :
m_self_object(p_self_object),
m_result(p_result),
m_exclude(p_exclude),
m_collided(false),
- m_min_distance(0) {}
+ m_min_distance(0),
+ collide_with_bodies(p_collide_with_bodies),
+ collide_with_areas(p_collide_with_areas) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;
diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp
index 97ea7ca3df..07fde6efb9 100644
--- a/modules/bullet/hinge_joint_bullet.cpp
+++ b/modules/bullet/hinge_joint_bullet.cpp
@@ -97,7 +97,7 @@ void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t
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");
+ WARN_PRINTS("HingeJoint doesn't support bias in the Bullet backend, so it's always 0.");
}
break;
case PhysicsServer::HINGE_JOINT_LIMIT_UPPER:
@@ -122,7 +122,7 @@ void HingeJointBullet::set_param(PhysicsServer::HingeJointParam p_param, real_t
hingeConstraint->setMaxMotorImpulse(p_value);
break;
default:
- WARN_PRINTS("The Bullet Hinge Joint doesn't support this parameter: " + itos(p_param) + ", value: " + itos(p_value));
+ WARN_PRINTS("HingeJoint doesn't support this parameter in the Bullet backend: " + itos(p_param) + ", value: " + itos(p_value));
}
}
@@ -146,7 +146,7 @@ real_t HingeJointBullet::get_param(PhysicsServer::HingeJointParam p_param) const
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));
+ WARN_PRINTS("HingeJoint doesn't support this parameter in the Bullet backend: " + itos(p_param));
return 0;
}
}
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 81a62edba6..9c0e802be5 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -265,8 +265,6 @@ RigidBodyBullet::RigidBodyBullet() :
angularDamp(0),
can_sleep(true),
omit_forces_integration(false),
- restitution_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT),
- friction_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT),
force_integration_callback(NULL),
isTransformChanged(false),
previousActiveState(true),
@@ -761,22 +759,6 @@ Vector3 RigidBodyBullet::get_angular_velocity() const {
return gVec;
}
-void RigidBodyBullet::set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode) {
- if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
- restitution_combine_mode = p_mode;
- } else {
- friction_combine_mode = p_mode;
- }
-}
-
-PhysicsServer::CombineMode RigidBodyBullet::get_combine_mode(PhysicsServer::BodyParameter p_param) const {
- if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
- return restitution_combine_mode;
- } else {
- return friction_combine_mode;
- }
-}
-
void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) {
if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
// The kinematic use MotionState class
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index 35af3b90d8..f03009bce9 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -203,9 +203,6 @@ private:
bool can_sleep;
bool omit_forces_integration;
- PhysicsServer::CombineMode restitution_combine_mode;
- PhysicsServer::CombineMode friction_combine_mode;
-
Vector<CollisionData> collisions;
// these parameters are used to avoid vector resize
int maxCollisionsDetection;
@@ -301,12 +298,6 @@ public:
void set_angular_velocity(const Vector3 &p_velocity);
Vector3 get_angular_velocity() const;
- void set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode);
- PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const;
-
- _FORCE_INLINE_ PhysicsServer::CombineMode get_restitution_combine_mode() const { return restitution_combine_mode; }
- _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
-
virtual void set_transform__bullet(const btTransform &p_global_transform);
virtual const btTransform &get_transform__bullet() const;
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index e4c1a5f9b5..fab8d0cf3d 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -44,19 +44,20 @@
@author AndreaCatania
*/
-ShapeBullet::ShapeBullet() {}
+ShapeBullet::ShapeBullet() :
+ margin(0.04) {}
ShapeBullet::~ShapeBullet() {}
-btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_margin) {
+btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge) {
btVector3 s;
G_TO_B(p_implicit_scale, s);
- return create_bt_shape(s, p_margin);
+ return create_bt_shape(s, p_extra_edge);
}
btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
p_btShape->setUserPointer(const_cast<ShapeBullet *>(this));
- p_btShape->setMargin(0.);
+ p_btShape->setMargin(margin);
return p_btShape;
}
@@ -93,6 +94,15 @@ const Map<ShapeOwnerBullet *, int> &ShapeBullet::get_owners() const {
return owners;
}
+void ShapeBullet::set_margin(real_t p_margin) {
+ margin = p_margin;
+ notifyShapeChanged();
+}
+
+real_t ShapeBullet::get_margin() const {
+ return margin;
+}
+
btEmptyShape *ShapeBullet::create_shape_empty() {
return bulletnew(btEmptyShape);
}
@@ -166,7 +176,7 @@ void PlaneShapeBullet::setup(const Plane &p_plane) {
notifyShapeChanged();
}
-btCollisionShape *PlaneShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
+btCollisionShape *PlaneShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
btVector3 btPlaneNormal;
G_TO_B(plane.normal, btPlaneNormal);
return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d));
@@ -194,8 +204,8 @@ void SphereShapeBullet::setup(real_t p_radius) {
notifyShapeChanged();
}
-btCollisionShape *SphereShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
- return prepare(ShapeBullet::create_shape_sphere(radius * p_implicit_scale[0] + p_margin));
+btCollisionShape *SphereShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+ return prepare(ShapeBullet::create_shape_sphere(radius * p_implicit_scale[0] + p_extra_edge));
}
/* Box */
@@ -221,8 +231,8 @@ void BoxShapeBullet::setup(const Vector3 &p_half_extents) {
notifyShapeChanged();
}
-btCollisionShape *BoxShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
- return prepare(ShapeBullet::create_shape_box((half_extents * p_implicit_scale) + btVector3(p_margin, p_margin, p_margin)));
+btCollisionShape *BoxShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+ return prepare(ShapeBullet::create_shape_box((half_extents * p_implicit_scale) + btVector3(p_extra_edge, p_extra_edge, p_extra_edge)));
}
/* Capsule */
@@ -254,8 +264,8 @@ void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) {
notifyShapeChanged();
}
-btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
- return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin));
+btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+ return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_extra_edge, height * p_implicit_scale[1] + p_extra_edge));
}
/* Cylinder */
@@ -329,11 +339,10 @@ void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) {
notifyShapeChanged();
}
-btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
+btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
btCollisionShape *cs(ShapeBullet::create_shape_convex(vertices));
cs->setLocalScaling(p_implicit_scale);
prepare(cs);
- cs->setMargin(p_margin);
return cs;
}
@@ -402,14 +411,13 @@ void ConcavePolygonShapeBullet::setup(PoolVector<Vector3> p_faces) {
notifyShapeChanged();
}
-btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
+btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
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();
cs->setLocalScaling(p_implicit_scale);
prepare(cs);
- cs->setMargin(p_margin);
return cs;
}
@@ -495,11 +503,10 @@ void HeightMapShapeBullet::setup(PoolVector<real_t> &p_heights, int p_width, int
notifyShapeChanged();
}
-btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
+btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, min_height, max_height));
cs->setLocalScaling(p_implicit_scale);
prepare(cs);
- cs->setMargin(p_margin);
return cs;
}
@@ -533,6 +540,6 @@ void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) {
notifyShapeChanged();
}
-btCollisionShape *RayShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
- return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_margin, slips_on_slope));
+btCollisionShape *RayShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+ return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_extra_edge, slips_on_slope));
}
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
index 16a5ac1fc6..638e044e6a 100644
--- a/modules/bullet/shape_bullet.h
+++ b/modules/bullet/shape_bullet.h
@@ -52,6 +52,7 @@ class btBvhTriangleMeshShape;
class ShapeBullet : public RIDBullet {
Map<ShapeOwnerBullet *, int> owners;
+ real_t margin;
protected:
/// return self
@@ -62,14 +63,17 @@ public:
ShapeBullet();
virtual ~ShapeBullet();
- btCollisionShape *create_bt_shape(const Vector3 &p_implicit_scale, real_t p_margin = 0);
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0) = 0;
+ btCollisionShape *create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0) = 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;
+ void set_margin(real_t p_margin);
+ real_t get_margin() const;
+
/// Setup the shape
virtual void set_data(const Variant &p_data) = 0;
virtual Variant get_data() const = 0;
@@ -100,7 +104,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(const Plane &p_plane);
@@ -117,7 +121,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(real_t p_radius);
@@ -134,7 +138,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(const Vector3 &p_half_extents);
@@ -153,7 +157,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(real_t p_height, real_t p_radius);
@@ -189,7 +193,7 @@ public:
void get_vertices(Vector<Vector3> &out_vertices);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(const Vector<Vector3> &p_vertices);
@@ -207,7 +211,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(PoolVector<Vector3> p_faces);
@@ -227,7 +231,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(PoolVector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
@@ -244,7 +248,7 @@ public:
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
- virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
+ virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
void setup(real_t p_length, bool p_slips_on_slope);
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index 1686a6e87e..9fc7230f91 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -123,7 +123,7 @@ void SoftBodyBullet::update_visual_server(SoftBodyVisualServerHandler *p_visual_
void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) {
- if (p_mesh.is_null() || !p_mesh->surface_is_softbody_friendly(0))
+ if (p_mesh.is_null())
soft_mesh.unref();
else
soft_mesh = p_mesh;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 8454bea4eb..b5329bc347 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -61,7 +61,7 @@ BulletPhysicsDirectSpaceState::BulletPhysicsDirectSpaceState(SpaceBullet *p_spac
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_mask) {
+int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (p_result_max <= 0)
return 0;
@@ -69,13 +69,13 @@ int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, Shape
btVector3 bt_point;
G_TO_B(p_point, bt_point);
- btSphereShape sphere_point(0.f);
+ btSphereShape sphere_point(0.001f);
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);
+ GodotAllContactResultCallback btResult(&collision_object_point, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas);
btResult.m_collisionFilterGroup = 0;
btResult.m_collisionFilterMask = p_collision_mask;
space->dynamicsWorld->contactTest(&collision_object_point, btResult);
@@ -84,7 +84,7 @@ int BulletPhysicsDirectSpaceState::intersect_point(const Vector3 &p_point, Shape
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_mask, bool p_pick_ray) {
+bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_ray) {
btVector3 btVec_from;
btVector3 btVec_to;
@@ -93,7 +93,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V
G_TO_B(p_to, btVec_to);
// setup query
- GodotClosestRayResultCallback btResult(btVec_from, btVec_to, &p_exclude);
+ GodotClosestRayResultCallback btResult(btVec_from, btVec_to, &p_exclude, p_collide_with_bodies, p_collide_with_areas);
btResult.m_collisionFilterGroup = 0;
btResult.m_collisionFilterMask = p_collision_mask;
btResult.m_pickRay = p_pick_ray;
@@ -117,7 +117,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V
}
}
-int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask) {
+int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (p_result_max <= 0)
return 0;
@@ -139,7 +139,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
collision_object.setCollisionShape(btConvex);
collision_object.setWorldTransform(bt_xform);
- GodotAllContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude);
+ GodotAllContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas);
btQuery.m_collisionFilterGroup = 0;
btQuery.m_collisionFilterMask = p_collision_mask;
btQuery.m_closestDistanceThreshold = 0;
@@ -150,7 +150,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
return btQuery.m_count;
}
-bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &p_closest_safe, float &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, ShapeRestInfo *r_info) {
+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_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) {
ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape);
btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale(), p_margin);
@@ -171,7 +171,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
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);
+ GodotClosestConvexResultCallback btResult(bt_xform_from.getOrigin(), bt_xform_to.getOrigin(), &p_exclude, p_collide_with_bodies, p_collide_with_areas);
btResult.m_collisionFilterGroup = 0;
btResult.m_collisionFilterMask = p_collision_mask;
@@ -197,7 +197,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
}
/// Returns the list of contacts pairs in this order: Local contact, other body contact
-bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask) {
+bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
if (p_result_max <= 0)
return 0;
@@ -219,7 +219,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &
collision_object.setCollisionShape(btConvex);
collision_object.setWorldTransform(bt_xform);
- GodotContactPairContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude);
+ GodotContactPairContactResultCallback btQuery(&collision_object, r_results, p_result_max, &p_exclude, p_collide_with_bodies, p_collide_with_areas);
btQuery.m_collisionFilterGroup = 0;
btQuery.m_collisionFilterMask = p_collision_mask;
btQuery.m_closestDistanceThreshold = 0;
@@ -231,7 +231,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &
return btQuery.m_count;
}
-bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask) {
+bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get(p_shape);
@@ -251,7 +251,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh
collision_object.setCollisionShape(btConvex);
collision_object.setWorldTransform(bt_xform);
- GodotRestInfoContactResultCallback btQuery(&collision_object, r_info, &p_exclude);
+ GodotRestInfoContactResultCallback btQuery(&collision_object, r_info, &p_exclude, p_collide_with_bodies, p_collide_with_areas);
btQuery.m_collisionFilterGroup = 0;
btQuery.m_collisionFilterMask = p_collision_mask;
btQuery.m_closestDistanceThreshold = 0;
@@ -554,42 +554,12 @@ BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() {
btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) {
- const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_restitution_combine_mode();
-
- switch (cm) {
- case PhysicsServer::COMBINE_MODE_INHERIT:
- if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_restitution_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
- return calculateGodotCombinedRestitution(body1, body0);
- // else use MAX [This is used when the two bodies doesn't use physical material]
- case PhysicsServer::COMBINE_MODE_MAX:
- return MAX(body0->getRestitution(), body1->getRestitution());
- case PhysicsServer::COMBINE_MODE_MIN:
- return MIN(body0->getRestitution(), body1->getRestitution());
- case PhysicsServer::COMBINE_MODE_MULTIPLY:
- return body0->getRestitution() * body1->getRestitution();
- default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
- return (body0->getRestitution() + body1->getRestitution()) / 2;
- }
+ return CLAMP(body0->getRestitution() + body1->getRestitution(), 0, 1);
}
btScalar calculateGodotCombinedFriction(const btCollisionObject *body0, const btCollisionObject *body1) {
- const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_friction_combine_mode();
-
- switch (cm) {
- case PhysicsServer::COMBINE_MODE_INHERIT:
- if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
- return calculateGodotCombinedFriction(body1, body0);
- // else use MULTIPLY [This is used when the two bodies doesn't use physical material]
- case PhysicsServer::COMBINE_MODE_MULTIPLY:
- return body0->getFriction() * body1->getFriction();
- case PhysicsServer::COMBINE_MODE_MAX:
- return MAX(body0->getFriction(), body1->getFriction());
- case PhysicsServer::COMBINE_MODE_MIN:
- return MIN(body0->getFriction(), body1->getFriction());
- default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
- return (body0->getFriction() * body1->getFriction()) / 2;
- }
+ return ABS(MIN(body0->getFriction(), body1->getFriction()));
}
void SpaceBullet::create_empty_world(bool p_create_soft_world) {
@@ -849,7 +819,7 @@ static Ref<SpatialMaterial> red_mat;
static Ref<SpatialMaterial> blue_mat;
#endif
-bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result) {
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes) {
#if debug_test_motion
/// Yes I know this is not good, but I've used it as fast debugging hack.
@@ -924,6 +894,12 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
// Skip no convex shape
continue;
}
+
+ if (p_exclude_raycast_shapes && p_body->get_bt_shape(shIndex)->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) {
+ // Skip rayshape in order to implement custom separation process
+ continue;
+ }
+
btConvexShape *convex_shape_test(static_cast<btConvexShape *>(p_body->get_bt_shape(shIndex)));
btTransform shape_world_from = body_transform * p_body->get_kinematic_utilities()->shapes[shIndex].transform;
@@ -954,11 +930,11 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
btVector3 __rec(0, 0, 0);
RecoverResult r_recover_result;
- has_penetration = recover_from_penetration(p_body, body_transform, 0, p_infinite_inertia, __rec, &r_recover_result);
+ has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result);
// Parse results
if (r_result) {
- B_TO_G(motion + initial_recover_motion, r_result->motion);
+ B_TO_G(motion + initial_recover_motion + __rec, r_result->motion);
if (has_penetration) {
@@ -994,6 +970,39 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
return has_penetration;
}
+int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin) {
+
+ btTransform body_transform;
+ G_TO_B(p_transform, body_transform);
+ UNSCALE_BT_BASIS(body_transform);
+
+ btVector3 recover_motion(0, 0, 0);
+
+ int rays_found;
+
+ for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
+ int last_ray_index = recover_from_penetration_ray(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, p_result_max, recover_motion, r_results);
+
+ rays_found = MAX(last_ray_index, rays_found);
+ if (!rays_found) {
+ break;
+ } else {
+ body_transform.getOrigin() += recover_motion;
+ }
+ }
+
+ //optimize results (remove non colliding)
+ for (int i = 0; i < rays_found; i++) {
+ if (r_results[i].collision_depth >= 0) {
+ rays_found--;
+ SWAP(r_results[i], r_results[rays_found]);
+ }
+ }
+
+ B_TO_G(recover_motion, r_recover_motion);
+ return rays_found;
+}
+
struct RecoverPenetrationBroadPhaseCallback : public btBroadphaseAabbCallback {
private:
const btCollisionObject *self_collision_object;
@@ -1050,6 +1059,11 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
continue;
}
+ if (kin_shape.shape->getShapeType() == CUSTOM_CONVEX_SHAPE_TYPE) {
+ // Skip rayshape in order to implement custom separation process
+ continue;
+ }
+
body_shape_position = p_body_position * kin_shape.transform;
body_shape_position_recovered = body_shape_position;
body_shape_position_recovered.getOrigin() += r_delta_recover_movement;
@@ -1152,7 +1166,6 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC
if (contactPointResult.hasHit()) {
r_delta_recover_movement += contactPointResult.m_pointNormalWorld * (contactPointResult.m_penetration_distance * -1 * p_recover_movement_scale);
-
if (r_recover_result) {
if (contactPointResult.m_penetration_distance < r_recover_result->penetration_distance) {
r_recover_result->hasPenetration = true;
@@ -1168,3 +1181,79 @@ bool SpaceBullet::RFP_convex_world_test(const btConvexShape *p_shapeA, const btC
}
return false;
}
+
+int SpaceBullet::recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results) {
+
+ RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask());
+
+ btTransform body_shape_position;
+ btTransform body_shape_position_recovered;
+
+ // Broad phase support
+ btVector3 minAabb, maxAabb;
+
+ int ray_index = 0;
+
+ // For each shape
+ for (int kinIndex = p_body->get_kinematic_utilities()->shapes.size() - 1; 0 <= kinIndex; --kinIndex) {
+
+ recover_broad_result.reset();
+
+ if (ray_index >= p_result_max) {
+ break;
+ }
+
+ const RigidBodyBullet::KinematicShape &kin_shape(p_body->get_kinematic_utilities()->shapes[kinIndex]);
+ if (!kin_shape.is_active()) {
+ continue;
+ }
+
+ if (kin_shape.shape->getShapeType() != CUSTOM_CONVEX_SHAPE_TYPE) {
+ continue;
+ }
+
+ body_shape_position = p_body_position * kin_shape.transform;
+ body_shape_position_recovered = body_shape_position;
+ body_shape_position_recovered.getOrigin() += r_delta_recover_movement;
+
+ kin_shape.shape->getAabb(body_shape_position_recovered, minAabb, maxAabb);
+ dynamicsWorld->getBroadphase()->aabbTest(minAabb, maxAabb, recover_broad_result);
+
+ for (int i = recover_broad_result.result_collision_objects.size() - 1; 0 <= i; --i) {
+ btCollisionObject *otherObject = recover_broad_result.result_collision_objects[i];
+ if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) {
+ otherObject->activate(); // Force activation of hitten rigid, soft body
+ continue;
+ } else if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object()))
+ continue;
+
+ if (otherObject->getCollisionShape()->isCompound()) {
+
+ // Each convex shape
+ btCompoundShape *cs = static_cast<btCompoundShape *>(otherObject->getCollisionShape());
+ for (int x = cs->getNumChildShapes() - 1; 0 <= x; --x) {
+
+ RecoverResult r_recover_result;
+ if (RFP_convex_world_test(kin_shape.shape, cs->getChildShape(x), p_body->get_bt_collision_object(), otherObject, kinIndex, x, body_shape_position, otherObject->getWorldTransform() * cs->getChildTransform(x), p_recover_movement_scale, r_delta_recover_movement, &r_recover_result)) {
+
+ const btRigidBody *btRigid = static_cast<const btRigidBody *>(otherObject);
+ CollisionObjectBullet *collisionObject = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer());
+
+ r_results[ray_index].collision_depth = r_recover_result.penetration_distance;
+ B_TO_G(r_recover_result.pointWorld, r_results[ray_index].collision_point);
+ B_TO_G(r_recover_result.normal, r_results[ray_index].collision_normal);
+ B_TO_G(btRigid->getVelocityInLocalPoint(r_recover_result.pointWorld - btRigid->getWorldTransform().getOrigin()), r_results[ray_index].collider_velocity);
+ r_results[ray_index].collision_local_shape = kinIndex;
+ r_results[ray_index].collider_id = collisionObject->get_instance_id();
+ r_results[ray_index].collider = collisionObject->get_self();
+ r_results[ray_index].collider_shape = r_recover_result.other_compound_shape_index;
+ }
+ }
+ }
+ }
+
+ ++ray_index;
+ }
+
+ return ray_index;
+}
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index 6b86fc2f03..517ec67ffa 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -73,13 +73,13 @@ private:
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_mask = 0xFFFFFFFF);
- virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_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_mask = 0xFFFFFFFF);
- 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_mask = 0xFFFFFFFF, ShapeRestInfo *r_info = NULL);
+ virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false);
+ virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ 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_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, 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_mask = 0xFFFFFFFF);
- virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF);
+ virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
+ virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false);
virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const;
};
@@ -174,7 +174,8 @@ public:
void update_gravity();
- bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result);
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes);
+ int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin);
private:
void create_empty_world(bool p_create_soft_world);
@@ -208,5 +209,7 @@ private:
/// This is an API that recover a kinematic object from penetration
/// Using this we leave Bullet to select the best algorithm, For example GJK in case we have Convex Convex, or a Bullet accelerated algorithm
bool RFP_convex_world_test(const btConvexShape *p_shapeA, const btCollisionShape *p_shapeB, btCollisionObject *p_objectA, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL);
+
+ int recover_from_penetration_ray(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, int p_result_max, btVector3 &r_delta_recover_movement, PhysicsServer::SeparationResult *r_results);
};
#endif
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 53303a6533..2e07c23e28 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -34,9 +34,9 @@
#include "aabb.h"
#include "dvector.h"
#include "map.h"
-#include "math_2d.h"
#include "oa_hash_map.h"
#include "plane.h"
+#include "rect2.h"
#include "scene/resources/material.h"
#include "transform.h"
#include "vector3.h"
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index 3b1ddfe4c0..f9744c72af 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -32,7 +32,16 @@
///////////
-String CSGShapeSpatialGizmo::get_handle_name(int p_idx) const {
+CSGShapeSpatialGizmoPlugin::CSGShapeSpatialGizmoPlugin() {
+
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.2, 0.5, 1, 0.1));
+ create_material("shape_material", gizmo_color);
+ create_handle_material("handles");
+}
+
+String CSGShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere>(cs)) {
@@ -57,7 +66,9 @@ String CSGShapeSpatialGizmo::get_handle_name(int p_idx) const {
return "";
}
-Variant CSGShapeSpatialGizmo::get_handle_value(int p_idx) const {
+Variant CSGShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere>(cs)) {
@@ -89,10 +100,12 @@ Variant CSGShapeSpatialGizmo::get_handle_value(int p_idx) const {
return Variant();
}
-void CSGShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
+void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
Transform gt = cs->get_global_transform();
- gt.orthonormalize();
+ //gt.orthonormalize();
Transform gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
@@ -170,7 +183,9 @@ void CSGShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2
s->set_outer_radius(d);
}
}
-void CSGShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
+void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere>(cs)) {
CSGSphere *s = Object::cast_to<CSGSphere>(cs);
@@ -260,12 +275,26 @@ void CSGShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bo
ur->commit_action();
}
}
-void CSGShapeSpatialGizmo::redraw() {
+bool CSGShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
+ return Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial);
+}
- clear();
+String CSGShapeSpatialGizmoPlugin::get_name() const {
+ return "CSGShapes";
+}
+
+bool CSGShapeSpatialGizmoPlugin::is_selectable_when_hidden() const {
+ return true;
+}
- Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/csg");
- Ref<Material> material = create_material("shape_material", gizmo_color);
+void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
+
+ CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node());
+
+ p_gizmo->clear();
+
+ Ref<Material> material = get_material("shape_material", p_gizmo);
+ Ref<Material> handles_material = get_material("handles");
PoolVector<Vector3> faces = cs->get_brush_faces();
@@ -284,8 +313,8 @@ void CSGShapeSpatialGizmo::redraw() {
}
}
- add_lines(lines, material);
- add_collision_segments(lines);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
if (Object::cast_to<CSGSphere>(cs)) {
CSGSphere *s = Object::cast_to<CSGSphere>(cs);
@@ -293,7 +322,7 @@ void CSGShapeSpatialGizmo::redraw() {
float r = s->get_radius();
Vector<Vector3> handles;
handles.push_back(Vector3(r, 0, 0));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CSGBox>(cs)) {
@@ -303,7 +332,7 @@ void CSGShapeSpatialGizmo::redraw() {
handles.push_back(Vector3(s->get_width(), 0, 0));
handles.push_back(Vector3(0, s->get_height(), 0));
handles.push_back(Vector3(0, 0, s->get_depth()));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CSGCylinder>(cs)) {
@@ -312,7 +341,7 @@ void CSGShapeSpatialGizmo::redraw() {
Vector<Vector3> handles;
handles.push_back(Vector3(s->get_radius(), 0, 0));
handles.push_back(Vector3(0, s->get_height() * 0.5, 0));
- add_handles(handles);
+ p_gizmo->add_handles(handles, handles_material);
}
if (Object::cast_to<CSGTorus>(cs)) {
@@ -321,25 +350,11 @@ void CSGShapeSpatialGizmo::redraw() {
Vector<Vector3> handles;
handles.push_back(Vector3(s->get_inner_radius(), 0, 0));
handles.push_back(Vector3(s->get_outer_radius(), 0, 0));
- add_handles(handles);
- }
-}
-CSGShapeSpatialGizmo::CSGShapeSpatialGizmo(CSGShape *p_cs) {
-
- cs = p_cs;
- set_spatial_node(p_cs);
-}
-
-Ref<SpatialEditorGizmo> EditorPluginCSG::create_spatial_gizmo(Spatial *p_spatial) {
- if (Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial)) {
- Ref<CSGShapeSpatialGizmo> csg = memnew(CSGShapeSpatialGizmo(Object::cast_to<CSGShape>(p_spatial)));
- return csg;
+ p_gizmo->add_handles(handles, handles_material);
}
-
- return Ref<SpatialEditorGizmo>();
}
EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) {
-
- EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.2, 0.5, 1, 0.1));
+ Ref<CSGShapeSpatialGizmoPlugin> gizmo_plugin = Ref<CSGShapeSpatialGizmoPlugin>(memnew(CSGShapeSpatialGizmoPlugin));
+ SpatialEditor::get_singleton()->register_gizmo_plugin(gizmo_plugin);
}
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 68e916823b..d65d1f58c1 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -35,25 +35,27 @@
#include "editor/editor_plugin.h"
#include "editor/spatial_editor_gizmos.h"
-class CSGShapeSpatialGizmo : public EditorSpatialGizmo {
+class CSGShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
- GDCLASS(CSGShapeSpatialGizmo, EditorSpatialGizmo);
-
- CSGShape *cs;
+ GDCLASS(CSGShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
- virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
- void redraw();
- CSGShapeSpatialGizmo(CSGShape *p_cs = NULL);
+ bool has_gizmo(Spatial *p_spatial);
+ String get_name() const;
+ bool is_selectable_when_hidden() const;
+ void redraw(EditorSpatialGizmo *p_gizmo);
+
+ String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const;
+ void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point);
+ void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel);
+
+ CSGShapeSpatialGizmoPlugin();
};
class EditorPluginCSG : public EditorPlugin {
GDCLASS(EditorPluginCSG, EditorPlugin)
public:
- virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
EditorPluginCSG(EditorNode *p_editor);
};
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 9f2171a82a..258c628d93 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -161,8 +161,6 @@ CSGBrush *CSGShape::_get_brush() {
void CSGShape::_update_shape() {
- //print_line("updating shape for " + String(get_path()));
-
if (parent)
return;
@@ -372,7 +370,6 @@ void CSGShape::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- //print_line("local xform changed");
if (parent) {
parent->_make_dirty();
}
@@ -641,7 +638,6 @@ CSGBrush *CSGMesh::_build_brush() {
}
}
- //print_line("total vertices? " + itos(vertices.size()));
if (vertices.size() == 0)
return NULL;
diff --git a/modules/cvtt/SCsub b/modules/cvtt/SCsub
new file mode 100644
index 0000000000..5c396482aa
--- /dev/null
+++ b/modules/cvtt/SCsub
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+env_cvtt = env_modules.Clone()
+
+# Thirdparty source files
+if env['builtin_squish']:
+ thirdparty_dir = "#thirdparty/cvtt/"
+ thirdparty_sources = [
+ "ConvectionKernels.cpp"
+ ]
+
+ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+ env_cvtt.add_source_files(env.modules_sources, thirdparty_sources)
+ env_cvtt.Append(CPPPATH=[thirdparty_dir])
+
+# Godot source files
+env_cvtt.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/cvtt/config.py b/modules/cvtt/config.py
new file mode 100644
index 0000000000..098f1eafa9
--- /dev/null
+++ b/modules/cvtt/config.py
@@ -0,0 +1,5 @@
+def can_build(env, platform):
+ return env['tools']
+
+def configure(env):
+ pass
diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp
new file mode 100644
index 0000000000..3a371c8597
--- /dev/null
+++ b/modules/cvtt/image_compress_cvtt.cpp
@@ -0,0 +1,394 @@
+/*************************************************************************/
+/* image_compress_cvtt.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "image_compress_cvtt.h"
+
+#include "os/os.h"
+#include "os/thread.h"
+#include "print_string.h"
+
+#include <ConvectionKernels.h>
+
+struct CVTTCompressionJobParams {
+ bool is_hdr;
+ bool is_signed;
+ int bytes_per_pixel;
+
+ cvtt::Options options;
+};
+
+struct CVTTCompressionRowTask {
+ const uint8_t *in_mm_bytes;
+ uint8_t *out_mm_bytes;
+ int y_start;
+ int width;
+ int height;
+};
+
+struct CVTTCompressionJobQueue {
+ CVTTCompressionJobParams job_params;
+ const CVTTCompressionRowTask *job_tasks;
+ uint32_t num_tasks;
+ uint32_t current_task;
+};
+
+static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const CVTTCompressionRowTask &p_row_task) {
+ const uint8_t *in_bytes = p_row_task.in_mm_bytes;
+ uint8_t *out_bytes = p_row_task.out_mm_bytes;
+ int w = p_row_task.width;
+ int h = p_row_task.height;
+
+ int y_start = p_row_task.y_start;
+ int y_end = y_start + 4;
+
+ int bytes_per_pixel = p_job_params.bytes_per_pixel;
+ bool is_hdr = p_job_params.is_hdr;
+ bool is_signed = p_job_params.is_signed;
+
+ cvtt::PixelBlockU8 input_blocks_ldr[cvtt::NumParallelBlocks];
+ cvtt::PixelBlockF16 input_blocks_hdr[cvtt::NumParallelBlocks];
+
+ for (int x_start = 0; x_start < w; x_start += 4 * cvtt::NumParallelBlocks) {
+ int x_end = x_start + 4 * cvtt::NumParallelBlocks;
+
+ for (int y = y_start; y < y_end; y++) {
+ int first_input_element = (y - y_start) * 4;
+ const uint8_t *row_start;
+ if (y >= h) {
+ row_start = in_bytes + (h - 1) * (w * bytes_per_pixel);
+ } else {
+ row_start = in_bytes + y * (w * bytes_per_pixel);
+ }
+
+ for (int x = x_start; x < x_end; x++) {
+ const uint8_t *pixel_start;
+ if (x >= w) {
+ pixel_start = row_start + (w - 1) * bytes_per_pixel;
+ } else {
+ pixel_start = row_start + x * bytes_per_pixel;
+ }
+
+ int block_index = (x - x_start) / 4;
+ int block_element = (x - x_start) % 4 + first_input_element;
+ if (is_hdr) {
+ memcpy(input_blocks_hdr[block_index].m_pixels[block_element], pixel_start, bytes_per_pixel);
+ input_blocks_hdr[block_index].m_pixels[block_element][3] = 0x3c00; // 1.0 (unused)
+ } else {
+ memcpy(input_blocks_ldr[block_index].m_pixels[block_element], pixel_start, bytes_per_pixel);
+ }
+ }
+ }
+
+ uint8_t output_blocks[16 * cvtt::NumParallelBlocks];
+
+ if (is_hdr) {
+ if (is_signed) {
+ cvtt::Kernels::EncodeBC6HS(output_blocks, input_blocks_hdr, p_job_params.options);
+ } else {
+ cvtt::Kernels::EncodeBC6HU(output_blocks, input_blocks_hdr, p_job_params.options);
+ }
+ } else {
+ cvtt::Kernels::EncodeBC7(output_blocks, input_blocks_ldr, p_job_params.options);
+ }
+
+ int num_real_blocks = ((w - x_start) + 3) / 4;
+ if (num_real_blocks > cvtt::NumParallelBlocks) {
+ num_real_blocks = cvtt::NumParallelBlocks;
+ }
+
+ memcpy(out_bytes, output_blocks, 16 * num_real_blocks);
+ out_bytes += 16 * num_real_blocks;
+ }
+}
+
+static void _digest_job_queue(void *p_job_queue) {
+ CVTTCompressionJobQueue *job_queue = static_cast<CVTTCompressionJobQueue *>(p_job_queue);
+
+ for (int next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) {
+ _digest_row_task(job_queue->job_params, job_queue->job_tasks[next_task - 1]);
+ }
+}
+
+void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressSource p_source) {
+
+ if (p_image->get_format() >= Image::FORMAT_BPTC_RGBA)
+ return; //do not compress, already compressed
+
+ int w = p_image->get_width();
+ int h = p_image->get_height();
+
+ bool is_ldr = (p_image->get_format() <= Image::FORMAT_RGBA8);
+ bool is_hdr = (p_image->get_format() == Image::FORMAT_RGBH);
+
+ if (!is_ldr && !is_hdr) {
+ return; // Not a usable source format
+ }
+
+ cvtt::Options options;
+ uint32_t flags = cvtt::Flags::Fastest;
+
+ if (p_lossy_quality > 0.85)
+ flags = cvtt::Flags::Ultra;
+ else if (p_lossy_quality > 0.75)
+ flags = cvtt::Flags::Better;
+ else if (p_lossy_quality > 0.55)
+ flags = cvtt::Flags::Default;
+ else if (p_lossy_quality > 0.35)
+ flags = cvtt::Flags::Fast;
+ else if (p_lossy_quality > 0.15)
+ flags = cvtt::Flags::Faster;
+
+ flags |= cvtt::Flags::BC7_RespectPunchThrough;
+
+ if (p_source == Image::COMPRESS_SOURCE_NORMAL) {
+ flags |= cvtt::Flags::Uniform;
+ }
+
+ Image::Format target_format = Image::FORMAT_BPTC_RGBA;
+
+ bool is_signed = false;
+ if (is_hdr) {
+ PoolVector<uint8_t>::Read rb = p_image->get_data().read();
+
+ const uint16_t *source_data = reinterpret_cast<const uint16_t *>(&rb[0]);
+ int pixel_element_count = w * h * 3;
+ for (int i = 0; i < pixel_element_count; i++) {
+ if ((source_data[i] & 0x8000) != 0 && (source_data[i] & 0x7fff) != 0) {
+ is_signed = true;
+ break;
+ }
+ }
+
+ target_format = is_signed ? Image::FORMAT_BPTC_RGBF : Image::FORMAT_BPTC_RGBFU;
+ } else {
+ p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
+ }
+
+ PoolVector<uint8_t>::Read rb = p_image->get_data().read();
+
+ PoolVector<uint8_t> data;
+ int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
+ int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
+ data.resize(target_size);
+ int shift = Image::get_format_pixel_rshift(target_format);
+
+ PoolVector<uint8_t>::Write wb = data.write();
+
+ int dst_ofs = 0;
+
+ CVTTCompressionJobQueue job_queue;
+ job_queue.job_params.is_hdr = is_hdr;
+ job_queue.job_params.is_signed = is_signed;
+ job_queue.job_params.options = options;
+ job_queue.job_params.bytes_per_pixel = is_hdr ? 6 : 4;
+
+#ifdef NO_THREADS
+ int num_job_threads = 0;
+#else
+ int num_job_threads = OS::get_singleton()->can_use_threads() ? (OS::get_singleton()->get_processor_count() - 1) : 0;
+#endif
+
+ PoolVector<CVTTCompressionRowTask> tasks;
+
+ for (int i = 0; i <= mm_count; i++) {
+
+ int bw = w % 4 != 0 ? w + (4 - w % 4) : w;
+ int bh = h % 4 != 0 ? h + (4 - h % 4) : h;
+
+ int src_ofs = p_image->get_mipmap_offset(i);
+
+ const uint8_t *in_bytes = &rb[src_ofs];
+ uint8_t *out_bytes = &wb[dst_ofs];
+
+ for (int y_start = 0; y_start < h; y_start += 4) {
+ int y_end = y_start + 4;
+
+ CVTTCompressionRowTask row_task;
+ row_task.width = w;
+ row_task.height = h;
+ row_task.y_start = y_start;
+ row_task.in_mm_bytes = in_bytes;
+ row_task.out_mm_bytes = out_bytes;
+
+ if (num_job_threads > 0) {
+ tasks.push_back(row_task);
+ } else {
+ _digest_row_task(job_queue.job_params, row_task);
+ }
+
+ out_bytes += 16 * (bw / 4);
+ }
+
+ dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift;
+ w >>= 1;
+ h >>= 1;
+ }
+
+ if (num_job_threads > 0) {
+ PoolVector<Thread *> threads;
+ threads.resize(num_job_threads);
+
+ PoolVector<Thread *>::Write threads_wb = threads.write();
+
+ PoolVector<CVTTCompressionRowTask>::Read tasks_rb = tasks.read();
+
+ job_queue.job_tasks = &tasks_rb[0];
+ job_queue.current_task = 0;
+ job_queue.num_tasks = static_cast<uint32_t>(tasks.size());
+
+ for (int i = 0; i < num_job_threads; i++) {
+ threads_wb[i] = Thread::create(_digest_job_queue, &job_queue);
+ }
+ _digest_job_queue(&job_queue);
+
+ for (int i = 0; i < num_job_threads; i++) {
+ Thread::wait_to_finish(threads_wb[i]);
+ memdelete(threads_wb[i]);
+ }
+ }
+
+ p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
+}
+
+void image_decompress_cvtt(Image *p_image) {
+
+ Image::Format target_format;
+ bool is_signed = false;
+ bool is_hdr = false;
+
+ Image::Format input_format = p_image->get_format();
+
+ switch (input_format) {
+ case Image::FORMAT_BPTC_RGBA:
+ target_format = Image::FORMAT_RGBA8;
+ break;
+ case Image::FORMAT_BPTC_RGBF:
+ case Image::FORMAT_BPTC_RGBFU:
+ target_format = Image::FORMAT_RGBH;
+ is_signed = (input_format == Image::FORMAT_BPTC_RGBF);
+ is_hdr = true;
+ break;
+ default:
+ return; // Invalid input format
+ };
+
+ int w = p_image->get_width();
+ int h = p_image->get_height();
+
+ PoolVector<uint8_t>::Read rb = p_image->get_data().read();
+
+ PoolVector<uint8_t> data;
+ int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
+ int mm_count = p_image->get_mipmap_count();
+ data.resize(target_size);
+ int shift = Image::get_format_pixel_rshift(target_format);
+
+ PoolVector<uint8_t>::Write wb = data.write();
+
+ int bytes_per_pixel = is_hdr ? 6 : 4;
+
+ int dst_ofs = 0;
+
+ for (int i = 0; i <= mm_count; i++) {
+
+ int src_ofs = p_image->get_mipmap_offset(i);
+
+ const uint8_t *in_bytes = &rb[src_ofs];
+ uint8_t *out_bytes = &wb[dst_ofs];
+
+ cvtt::PixelBlockU8 output_blocks_ldr[cvtt::NumParallelBlocks];
+ cvtt::PixelBlockF16 output_blocks_hdr[cvtt::NumParallelBlocks];
+
+ for (int y_start = 0; y_start < h; y_start += 4) {
+ int y_end = y_start + 4;
+
+ for (int x_start = 0; x_start < w; x_start += 4 * cvtt::NumParallelBlocks) {
+ int x_end = x_start + 4 * cvtt::NumParallelBlocks;
+
+ uint8_t input_blocks[16 * cvtt::NumParallelBlocks];
+ memset(input_blocks, 0, sizeof(input_blocks));
+
+ int num_real_blocks = ((w - x_start) + 3) / 4;
+ if (num_real_blocks > cvtt::NumParallelBlocks) {
+ num_real_blocks = cvtt::NumParallelBlocks;
+ }
+
+ memcpy(input_blocks, in_bytes, 16 * num_real_blocks);
+ in_bytes += 16 * num_real_blocks;
+
+ if (is_hdr) {
+ if (is_signed) {
+ cvtt::Kernels::DecodeBC6HS(output_blocks_hdr, input_blocks);
+ } else {
+ cvtt::Kernels::DecodeBC6HU(output_blocks_hdr, input_blocks);
+ }
+ } else {
+ cvtt::Kernels::DecodeBC7(output_blocks_ldr, input_blocks);
+ }
+
+ for (int y = y_start; y < y_end; y++) {
+ int first_input_element = (y - y_start) * 4;
+ uint8_t *row_start;
+ if (y >= h) {
+ row_start = out_bytes + (h - 1) * (w * bytes_per_pixel);
+ } else {
+ row_start = out_bytes + y * (w * bytes_per_pixel);
+ }
+
+ for (int x = x_start; x < x_end; x++) {
+ uint8_t *pixel_start;
+ if (x >= w) {
+ pixel_start = row_start + (w - 1) * bytes_per_pixel;
+ } else {
+ pixel_start = row_start + x * bytes_per_pixel;
+ }
+
+ int block_index = (x - x_start) / 4;
+ int block_element = (x - x_start) % 4 + first_input_element;
+ if (is_hdr) {
+ memcpy(pixel_start, output_blocks_hdr[block_index].m_pixels[block_element], bytes_per_pixel);
+ } else {
+ memcpy(pixel_start, output_blocks_ldr[block_index].m_pixels[block_element], bytes_per_pixel);
+ }
+ }
+ }
+ }
+ }
+
+ dst_ofs += w * h * bytes_per_pixel;
+ w >>= 1;
+ h >>= 1;
+ }
+
+ rb = PoolVector<uint8_t>::Read();
+ wb = PoolVector<uint8_t>::Write();
+
+ p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
+}
diff --git a/modules/cvtt/image_compress_cvtt.h b/modules/cvtt/image_compress_cvtt.h
new file mode 100644
index 0000000000..0e18b247e5
--- /dev/null
+++ b/modules/cvtt/image_compress_cvtt.h
@@ -0,0 +1,39 @@
+/*************************************************************************/
+/* image_compress_cvtt.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef IMAGE_COMPRESS_CVTT_H
+#define IMAGE_COMPRESS_CVTT_H
+
+#include "image.h"
+
+void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressSource p_source);
+void image_decompress_cvtt(Image *p_image);
+
+#endif // IMAGE_COMPRESS_CVTT_H
diff --git a/modules/cvtt/register_types.cpp b/modules/cvtt/register_types.cpp
new file mode 100644
index 0000000000..c96fbbf340
--- /dev/null
+++ b/modules/cvtt/register_types.cpp
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 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"
+
+#ifdef TOOLS_ENABLED
+
+#include "image_compress_cvtt.h"
+
+void register_cvtt_types() {
+
+ Image::set_compress_bptc_func(image_compress_cvtt);
+ Image::_image_decompress_bptc = image_decompress_cvtt;
+}
+
+void unregister_cvtt_types() {}
+
+#endif
diff --git a/modules/cvtt/register_types.h b/modules/cvtt/register_types.h
new file mode 100644
index 0000000000..73de9728d3
--- /dev/null
+++ b/modules/cvtt/register_types.h
@@ -0,0 +1,34 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef TOOLS_ENABLED
+void register_cvtt_types();
+void unregister_cvtt_types();
+#endif
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 9424080b6d..3cb24d0407 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -217,8 +217,6 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
if (!(flags & DDSD_MIPMAPCOUNT))
mipmaps = 1;
- //print_line("found format: "+String(dds_format_info[dds_format].name));
-
PoolVector<uint8_t> src_data;
const DDSFormatInfo &info = dds_format_info[dds_format];
diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp
index 8a674bc8c1..f5c817c816 100644
--- a/modules/etc/image_etc.cpp
+++ b/modules/etc/image_etc.cpp
@@ -98,6 +98,33 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
Image::Format img_format = p_img->get_format();
Image::DetectChannels detected_channels = p_img->get_detected_channels();
+ if (p_source == Image::COMPRESS_SOURCE_LAYERED) {
+ //keep what comes in
+ switch (p_img->get_format()) {
+ case Image::FORMAT_L8: {
+ detected_channels = Image::DETECTED_L;
+ } break;
+ case Image::FORMAT_LA8: {
+ detected_channels = Image::DETECTED_LA;
+ } break;
+ case Image::FORMAT_R8: {
+ detected_channels = Image::DETECTED_R;
+ } break;
+ case Image::FORMAT_RG8: {
+ detected_channels = Image::DETECTED_RG;
+ } break;
+ case Image::FORMAT_RGB8: {
+ detected_channels = Image::DETECTED_RGB;
+ } break;
+ case Image::FORMAT_RGBA8:
+ case Image::FORMAT_RGBA4444:
+ case Image::FORMAT_RGBA5551: {
+ detected_channels = Image::DETECTED_RGBA;
+ } break;
+ default: {}
+ }
+ }
+
if (p_source == Image::COMPRESS_SOURCE_SRGB && (detected_channels == Image::DETECTED_R || detected_channels == Image::DETECTED_RG)) {
//R and RG do not support SRGB
detected_channels = Image::DETECTED_RGB;
@@ -147,7 +174,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
PoolVector<uint8_t>::Read r = img->get_data().read();
- int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps() ? -1 : 0);
+ int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps());
int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0);
PoolVector<uint8_t> dst_data;
@@ -172,7 +199,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
int wofs = 0;
- print_line("begin encoding, format: " + Image::get_format_name(etc_format));
+ print_verbose("ETC: Begin encoding, format: " + Image::get_format_name(etc_format));
uint64_t t = OS::get_singleton()->get_ticks_msec();
for (int i = 0; i < mmc; i++) {
// convert source image to internal etc2comp format (which is equivalent to Image::FORMAT_RGBAF)
@@ -200,7 +227,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f
delete[] src_rgba_f;
}
- print_line("time encoding: " + rtos(OS::get_singleton()->get_ticks_msec() - t));
+ print_verbose("ETC: Time encoding: " + rtos(OS::get_singleton()->get_ticks_msec() - t));
p_img->create(imgw, imgh, p_img->has_mipmaps(), etc_format, dst_data);
}
diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml
index 1d3053244b..37d5b79e7a 100644
--- a/modules/gdnative/doc_classes/NativeScript.xml
+++ b/modules/gdnative/doc_classes/NativeScript.xml
@@ -57,6 +57,10 @@
</member>
<member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library">
</member>
+ <member name="script_class_icon_path" type="String" setter="set_script_class_icon_path" getter="get_script_class_icon_path">
+ </member>
+ <member name="script_class_name" type="String" setter="set_script_class_name" getter="get_script_class_name">
+ </member>
</members>
<constants>
</constants>
diff --git a/modules/gdnative/gdnative/pool_arrays.cpp b/modules/gdnative/gdnative/pool_arrays.cpp
index 6688be1a0d..2b6b7a823a 100644
--- a/modules/gdnative/gdnative/pool_arrays.cpp
+++ b/modules/gdnative/gdnative/pool_arrays.cpp
@@ -35,7 +35,7 @@
#include "dvector.h"
#include "core/color.h"
-#include "core/math/math_2d.h"
+#include "core/math/vector2.h"
#include "core/math/vector3.h"
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/rect2.cpp b/modules/gdnative/gdnative/rect2.cpp
index 83c58db520..54b98fc4e5 100644
--- a/modules/gdnative/gdnative/rect2.cpp
+++ b/modules/gdnative/gdnative/rect2.cpp
@@ -30,7 +30,7 @@
#include "gdnative/rect2.h"
-#include "core/math/math_2d.h"
+#include "core/math/transform_2d.h"
#include "core/variant.h"
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/transform2d.cpp b/modules/gdnative/gdnative/transform2d.cpp
index c69607a18a..fa0e15d9d2 100644
--- a/modules/gdnative/gdnative/transform2d.cpp
+++ b/modules/gdnative/gdnative/transform2d.cpp
@@ -30,7 +30,7 @@
#include "gdnative/transform2d.h"
-#include "core/math/math_2d.h"
+#include "core/math/transform_2d.h"
#include "core/variant.h"
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative/vector2.cpp b/modules/gdnative/gdnative/vector2.cpp
index 9e40b42373..c7902e06ee 100644
--- a/modules/gdnative/gdnative/vector2.cpp
+++ b/modules/gdnative/gdnative/vector2.cpp
@@ -30,7 +30,7 @@
#include "gdnative/vector2.h"
-#include "core/math/math_2d.h"
+#include "core/math/vector2.h"
#include "core/variant.h"
#ifdef __cplusplus
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 217fd87c3e..e326d11a84 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -5876,6 +5876,14 @@
["int", "p_idx"],
["godot_object *", "p_object"]
]
+ },
+ {
+ "name": "godot_nativescript_profiling_add_data",
+ "return_type": "void",
+ "arguments": [
+ ["const char *", "p_signature"],
+ ["uint64_t", "p_line"]
+ ]
}
]
},
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index f28ba352ab..29bd9eec5a 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -68,6 +68,7 @@ typedef enum {
GODOT_PROPERTY_HINT_GLOBAL_DIR, ///< a directort path must be passed
GODOT_PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type
GODOT_PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines
+ GODOT_PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties
GODOT_PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
GODOT_PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
GODOT_PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
@@ -237,6 +238,8 @@ void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_i
void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object);
+void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time);
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp
index ace2ecac5c..72606c8340 100644
--- a/modules/gdnative/nativescript/godot_nativescript.cpp
+++ b/modules/gdnative/nativescript/godot_nativescript.cpp
@@ -365,6 +365,10 @@ void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object
return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object);
}
+void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time) {
+ NativeScriptLanguage::get_singleton()->profiling_add_data(StringName(p_signature), p_time);
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 23747af86b..608c7aa4a5 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -62,6 +62,11 @@ void NativeScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_library", "library"), &NativeScript::set_library);
ClassDB::bind_method(D_METHOD("get_library"), &NativeScript::get_library);
+ ClassDB::bind_method(D_METHOD("set_script_class_name", "class_name"), &NativeScript::set_script_class_name);
+ ClassDB::bind_method(D_METHOD("get_script_class_name"), &NativeScript::get_script_class_name);
+ ClassDB::bind_method(D_METHOD("set_script_class_icon_path", "icon_path"), &NativeScript::set_script_class_icon_path);
+ ClassDB::bind_method(D_METHOD("get_script_class_icon_path"), &NativeScript::get_script_class_icon_path);
+
ClassDB::bind_method(D_METHOD("get_class_documentation"), &NativeScript::get_class_documentation);
ClassDB::bind_method(D_METHOD("get_method_documentation", "method"), &NativeScript::get_method_documentation);
ClassDB::bind_method(D_METHOD("get_signal_documentation", "signal_name"), &NativeScript::get_signal_documentation);
@@ -69,6 +74,9 @@ void NativeScript::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library");
+ ADD_GROUP("Script Class", "script_class_");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_name"), "set_script_class_name", "get_script_class_name");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "script_class_icon_path", PROPERTY_HINT_FILE), "set_script_class_icon_path", "get_script_class_icon_path");
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new"));
}
@@ -131,6 +139,22 @@ Ref<GDNativeLibrary> NativeScript::get_library() const {
return library;
}
+void NativeScript::set_script_class_name(String p_type) {
+ script_class_name = p_type;
+}
+
+String NativeScript::get_script_class_name() const {
+ return script_class_name;
+}
+
+void NativeScript::set_script_class_icon_path(String p_icon_path) {
+ script_class_icon_path = p_icon_path;
+}
+
+String NativeScript::get_script_class_icon_path() const {
+ return script_class_icon_path;
+}
+
bool NativeScript::can_instance() const {
NativeScriptDesc *script_data = get_script_desc();
@@ -986,6 +1010,10 @@ NativeScriptLanguage::NativeScriptLanguage() {
has_objects_to_register = false;
mutex = Mutex::create();
#endif
+
+#ifdef DEBUG_ENABLED
+ profiling = false;
+#endif
}
NativeScriptLanguage::~NativeScriptLanguage() {
@@ -1060,7 +1088,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const
s->set_class_name(p_class_name);
return Ref<NativeScript>(s);
}
-bool NativeScriptLanguage::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, Set<int> *r_safe_lines) const {
+bool NativeScriptLanguage::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, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
return true;
}
@@ -1128,17 +1156,105 @@ void NativeScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_
}
void NativeScriptLanguage::profiling_start() {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ profile_data.clear();
+ profiling = true;
+#endif
}
void NativeScriptLanguage::profiling_stop() {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ profiling = false;
+#endif
}
int NativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+ int current = 0;
+
+ for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ if (current >= p_info_max)
+ break;
+
+ p_info_arr[current].call_count = d->get().call_count;
+ p_info_arr[current].self_time = d->get().self_time;
+ p_info_arr[current].total_time = d->get().total_time;
+ p_info_arr[current].signature = d->get().signature;
+ current++;
+ }
+
+ return current;
+#else
return 0;
+#endif
}
int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+ int current = 0;
+
+ for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ if (current >= p_info_max)
+ break;
+
+ if (d->get().last_frame_call_count) {
+ p_info_arr[current].call_count = d->get().last_frame_call_count;
+ p_info_arr[current].self_time = d->get().last_frame_self_time;
+ p_info_arr[current].total_time = d->get().last_frame_total_time;
+ p_info_arr[current].signature = d->get().signature;
+ current++;
+ }
+ }
+
+ return current;
+#else
return 0;
+#endif
+}
+
+void NativeScriptLanguage::profiling_add_data(StringName p_signature, uint64_t p_time) {
+#ifdef DEBUG_ENABLED
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ Map<StringName, ProfileData>::Element *d = profile_data.find(p_signature);
+ if (d) {
+ d->get().call_count += 1;
+ d->get().total_time += p_time;
+ d->get().frame_call_count += 1;
+ d->get().frame_total_time += p_time;
+ } else {
+ ProfileData data;
+
+ data.signature = p_signature;
+ data.call_count = 1;
+ data.self_time = 0;
+ data.total_time = p_time;
+ data.frame_call_count = 1;
+ data.frame_self_time = 0;
+ data.frame_total_time = p_time;
+ data.last_frame_call_count = 0;
+ data.last_frame_self_time = 0;
+ data.last_frame_total_time = 0;
+
+ profile_data.insert(p_signature, data);
+ }
+#endif
}
int NativeScriptLanguage::register_binding_functions(godot_instance_binding_functions p_binding_functions) {
@@ -1381,6 +1497,24 @@ void NativeScriptLanguage::frame() {
has_objects_to_register = false;
}
#endif
+
+#ifdef DEBUG_ENABLED
+ {
+#ifndef NO_THREADS
+ MutexLock lock(mutex);
+#endif
+
+ for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ d->get().last_frame_call_count = d->get().frame_call_count;
+ d->get().last_frame_self_time = d->get().frame_self_time;
+ d->get().last_frame_total_time = d->get().frame_total_time;
+ d->get().frame_call_count = 0;
+ d->get().frame_self_time = 0;
+ d->get().frame_total_time = 0;
+ }
+ }
+#endif
+
call_libraries_cb(_frame_call_name);
}
@@ -1396,6 +1530,22 @@ void NativeScriptLanguage::thread_exit() {
#endif // NO_THREADS
+bool NativeScriptLanguage::handles_global_class_type(const String &p_type) const {
+ return p_type == "NativeScript";
+}
+
+String NativeScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
+ Ref<NativeScript> script = ResourceLoader::load(p_path, "NativeScript");
+ if (script.is_valid()) {
+ *r_base_type = script->get_instance_base_type();
+ *r_icon_path = script->get_script_class_icon_path();
+ return script->get_script_class_name();
+ }
+ *r_base_type = String();
+ *r_icon_path = String();
+ return String();
+}
+
void NativeReloadNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification);
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index 1b39b63ad9..6f18e2db27 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -118,6 +118,9 @@ class NativeScript : public Script {
String class_name;
+ String script_class_name;
+ String script_class_icon_path;
+
#ifndef NO_THREADS
Mutex *owners_lock;
#endif
@@ -135,6 +138,11 @@ public:
void set_library(Ref<GDNativeLibrary> p_library);
Ref<GDNativeLibrary> get_library() const;
+ void set_script_class_name(String p_type);
+ String get_script_class_name() const;
+ void set_script_class_icon_path(String p_icon_path);
+ String get_script_class_icon_path() const;
+
virtual bool can_instance() const;
virtual Ref<Script> get_base_script() const; //for script inheritance
@@ -246,6 +254,22 @@ private:
Map<int, HashMap<StringName, const void *> > global_type_tags;
+ struct ProfileData {
+ StringName signature;
+ uint64_t call_count;
+ uint64_t self_time;
+ uint64_t total_time;
+ uint64_t frame_call_count;
+ uint64_t frame_self_time;
+ uint64_t frame_total_time;
+ uint64_t last_frame_call_count;
+ uint64_t last_frame_self_time;
+ uint64_t last_frame_total_time;
+ };
+
+ Map<StringName, ProfileData> profile_data;
+ bool profiling;
+
public:
// These two maps must only be touched on the main thread
Map<String, Map<StringName, NativeScriptDesc> > library_classes;
@@ -295,7 +319,7 @@ public:
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, Set<int> *r_safe_lines = NULL) 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, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
@@ -332,6 +356,11 @@ public:
void set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag);
const void *get_global_type_tag(int p_idx, StringName p_class_name) const;
+
+ virtual bool handles_global_class_type(const String &p_type) const;
+ virtual String get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const;
+
+ void profiling_add_data(StringName p_signature, uint64_t p_time);
};
inline NativeScriptDesc *NativeScript::get_script_desc() const {
diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp
index 816b0f0cab..2b538c4a36 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_language.cpp
@@ -108,7 +108,7 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const
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, Set<int> *r_safe_lines) const {
+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, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
PoolStringArray functions;
if (_desc.validate) {
bool ret = _desc.validate(
diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h
index 2443e31361..c4df6f3a33 100644
--- a/modules/gdnative/pluginscript/pluginscript_language.h
+++ b/modules/gdnative/pluginscript/pluginscript_language.h
@@ -74,7 +74,7 @@ public:
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, Set<int> *r_safe_lines = NULL) 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, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index cff3be76ae..e05bc7d591 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -181,7 +181,11 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallErro
bool GDScript::can_instance() const {
- return valid || (!tool && !ScriptServer::is_scripting_enabled());
+#ifdef TOOLS_ENABLED
+ return valid && (tool || ScriptServer::is_scripting_enabled());
+#else
+ return valid;
+#endif
}
Ref<Script> GDScript::get_base_script() const {
@@ -290,11 +294,6 @@ bool GDScript::get_property_default_value(const StringName &p_property, Variant
#ifdef TOOLS_ENABLED
- /*
- for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) {
- print_line("\t"+String(String(I->key())+":"+String(I->get())));
- }
- */
const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property);
if (E) {
r_value = E->get();
@@ -310,27 +309,6 @@ bool GDScript::get_property_default_value(const StringName &p_property, Variant
ScriptInstance *GDScript::instance_create(Object *p_this) {
- if (!tool && !ScriptServer::is_scripting_enabled()) {
-
-#ifdef TOOLS_ENABLED
-
- //instance a fake script for editing the values
- //plist.invert();
-
- /*print_line("CREATING PLACEHOLDER");
- for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
- print_line(E->get().name);
- }*/
- PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this));
- placeholders.insert(si);
- //_update_placeholder(si);
- _update_exports();
- return si;
-#else
- return NULL;
-#endif
- }
-
GDScript *top = this;
while (top->_base)
top = top->_base;
@@ -349,6 +327,18 @@ ScriptInstance *GDScript::instance_create(Object *p_this) {
Variant::CallError unchecked_error;
return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error);
}
+
+PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) {
+#ifdef TOOLS_ENABLED
+ PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this));
+ placeholders.insert(si);
+ _update_exports();
+ return si;
+#else
+ return NULL;
+#endif
+}
+
bool GDScript::instance_has(const Object *p_this) const {
#ifndef NO_THREADS
@@ -405,7 +395,6 @@ bool GDScript::_update_exports() {
bool changed = false;
if (source_changed_cache) {
- //print_line("updating source for "+get_path());
source_changed_cache = false;
changed = true;
@@ -452,11 +441,8 @@ bool GDScript::_update_exports() {
if (bf.is_valid()) {
- //print_line("parent is: "+bf->get_path());
base_cache = bf;
bf->inheriters_cache.insert(get_instance_id());
-
- //bf->_update_exports(p_instances,true,false);
}
} else {
ERR_PRINT(("Path extending itself in " + path).utf8().get_data());
@@ -471,7 +457,6 @@ bool GDScript::_update_exports() {
continue;
members_cache.push_back(c->variables[i]._export);
- //print_line("found "+c->variables[i]._export.name);
member_default_values_cache[c->variables[i].identifier] = c->variables[i].default_value;
}
@@ -480,9 +465,12 @@ bool GDScript::_update_exports() {
for (int i = 0; i < c->_signals.size(); i++) {
_signals[c->_signals[i].name] = c->_signals[i].arguments;
}
+ } else {
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->set_build_failed(true);
+ }
}
} else {
- //print_line("unchanged is "+get_path());
}
if (base_cache.is_valid()) {
@@ -491,17 +479,15 @@ bool GDScript::_update_exports() {
}
}
- if (/*changed &&*/ placeholders.size()) { //hm :(
+ if (placeholders.size()) { //hm :(
- //print_line("updating placeholders for "+get_path());
-
- //update placeholders if any
+ // 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()->set_build_failed(false);
E->get()->update(propnames, values);
}
}
@@ -521,7 +507,6 @@ void GDScript::update_exports() {
Set<ObjectID> copy = inheriters_cache; //might get modified
- //print_line("update exports for "+get_path()+" ic: "+itos(copy.size()));
for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
Object *id = ObjectDB::get_instance(E->get());
GDScript *s = Object::cast_to<GDScript>(id);
@@ -596,6 +581,15 @@ Error GDScript::reload(bool p_keep_state) {
return err;
}
}
+#if DEBUG_ENABLED
+ for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) {
+ const GDScriptWarning &warning = E->get();
+ if (ScriptDebugger::get_singleton()) {
+ Vector<ScriptLanguage::StackInfo> si;
+ ScriptDebugger::get_singleton()->send_error("", get_path(), warning.line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si);
+ }
+ }
+#endif
valid = true;
@@ -808,7 +802,6 @@ Error GDScript::load_source_code(const String &p_path) {
#ifdef TOOLS_ENABLED
source_changed_cache = true;
#endif
- //print_line("LSC :"+get_path());
path = p_path;
return OK;
}
@@ -1490,7 +1483,6 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time;
p_info_arr[current].total_time = elem->self()->profile.last_frame_total_time;
p_info_arr[current].signature = elem->self()->profile.signature;
- //print_line(String(elem->self()->profile.signature)+": "+itos(elem->self()->profile.last_frame_call_count));
current++;
}
elem = elem->next();
@@ -1529,7 +1521,7 @@ struct GDScriptDepSort {
void GDScriptLanguage::reload_all_scripts() {
#ifdef DEBUG_ENABLED
- print_line("RELOAD ALL SCRIPTS");
+ print_verbose("GDScript: Reloading all scripts");
if (lock) {
lock->lock();
}
@@ -1539,7 +1531,7 @@ void GDScriptLanguage::reload_all_scripts() {
SelfList<GDScript> *elem = script_list.first();
while (elem) {
if (elem->self()->get_path().is_resource_file()) {
- print_line("FOUND: " + elem->self()->get_path());
+ print_verbose("GDScript: Found: " + elem->self()->get_path());
scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
}
elem = elem->next();
@@ -1555,7 +1547,7 @@ void GDScriptLanguage::reload_all_scripts() {
for (List<Ref<GDScript> >::Element *E = scripts.front(); E; E = E->next()) {
- print_line("RELOADING: " + E->get()->get_path());
+ print_verbose("GDScript: Reloading: " + E->get()->get_path());
E->get()->load_source_code(E->get()->get_path());
E->get()->reload(true);
}
@@ -1686,7 +1678,6 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
void GDScriptLanguage::frame() {
- //print_line("calls: "+itos(calls));
calls = 0;
#ifdef DEBUG_ENABLED
@@ -1796,7 +1787,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
return p_type == "GDScript";
}
-String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type) const {
+String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
PoolVector<uint8_t> sourcef;
Error err;
@@ -1861,12 +1852,174 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
}
}
+ if (r_icon_path) {
+ if (c->icon_path.empty() || c->icon_path.is_abs_path())
+ *r_icon_path = c->icon_path;
+ else if (c->icon_path.is_rel_path())
+ *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
+ }
return c->name;
}
return String();
}
+#ifdef DEBUG_ENABLED
+String GDScriptWarning::get_message() const {
+
+#define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String());
+
+ switch (code) {
+ case UNASSIGNED_VARIABLE_OP_ASSIGN: {
+ CHECK_SYMBOLS(1);
+ return "Using assignment with operation but the variable '" + symbols[0] + "' was not previously assigned a value.";
+ } break;
+ case UNASSIGNED_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "The variable '" + symbols[0] + "' was used but never assigned a value.";
+ } break;
+ case UNUSED_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "The local variable '" + symbols[0] + "' is declared but never used in the block.";
+ } break;
+ case UNUSED_CLASS_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "The class variable '" + symbols[0] + "' is declared but never used in the script.";
+ } break;
+ case UNUSED_ARGUMENT: {
+ CHECK_SYMBOLS(2);
+ return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'.";
+ } break;
+ case UNREACHABLE_CODE: {
+ CHECK_SYMBOLS(1);
+ return "Unreachable code (statement after return) in function '" + symbols[0] + "()'.";
+ } break;
+ case STANDALONE_EXPRESSION: {
+ return "Standalone expression (the line has no effect).";
+ } break;
+ case VOID_ASSIGNMENT: {
+ CHECK_SYMBOLS(1);
+ return "Assignment operation, but the function '" + symbols[0] + "()' returns void.";
+ } break;
+ case NARROWING_CONVERSION: {
+ return "Narrowing coversion (float is converted to int and lose precision).";
+ } break;
+ case FUNCTION_MAY_YIELD: {
+ CHECK_SYMBOLS(1);
+ return "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a GDScriptFunctionState instead.";
+ } break;
+ case VARIABLE_CONFLICTS_FUNCTION: {
+ CHECK_SYMBOLS(1);
+ return "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name.";
+ } break;
+ case FUNCTION_CONFLICTS_VARIABLE: {
+ CHECK_SYMBOLS(1);
+ return "Function declaration of '" + symbols[0] + "()' conflicts with a variable of the same name.";
+ } break;
+ case FUNCTION_CONFLICTS_CONSTANT: {
+ CHECK_SYMBOLS(1);
+ return "Function declaration of '" + symbols[0] + "()' conflicts with a constant of the same name.";
+ } break;
+ case INCOMPATIBLE_TERNARY: {
+ return "Values of the ternary conditional are not mutually compatible.";
+ } break;
+ case UNUSED_SIGNAL: {
+ CHECK_SYMBOLS(1);
+ return "The signal '" + symbols[0] + "' is declared but never emitted.";
+ } break;
+ case RETURN_VALUE_DISCARDED: {
+ CHECK_SYMBOLS(1);
+ return "The function '" + symbols[0] + "()' returns a value, but this value is never used.";
+ } break;
+ case PROPERTY_USED_AS_FUNCTION: {
+ CHECK_SYMBOLS(2);
+ return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a property with the same name. Did you mean to access it?";
+ } break;
+ case CONSTANT_USED_AS_FUNCTION: {
+ CHECK_SYMBOLS(2);
+ return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a constant with the same name. Did you mean to access it?";
+ } break;
+ case FUNCTION_USED_AS_PROPERTY: {
+ CHECK_SYMBOLS(2);
+ return "The property '" + symbols[0] + "' was not found in base '" + symbols[1] + "' but there's a method with the same name. Did you mean to call it?";
+ } break;
+ case INTEGER_DIVISION: {
+ return "Integer division, decimal part will be discarded.";
+ } break;
+ case UNSAFE_PROPERTY_ACCESS: {
+ CHECK_SYMBOLS(2);
+ return "The property '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
+ } break;
+ case UNSAFE_METHOD_ACCESS: {
+ CHECK_SYMBOLS(2);
+ return "The method '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype).";
+ } break;
+ case UNSAFE_CAST: {
+ CHECK_SYMBOLS(1);
+ return "The value is cast to '" + symbols[0] + "' but has an unkown type.";
+ } break;
+ case UNSAFE_CALL_ARGUMENT: {
+ CHECK_SYMBOLS(4);
+ return "The argument '" + symbols[0] + "' of the function '" + symbols[1] + "' requires a the subtype '" + symbols[2] + "' but the supertype '" + symbols[3] + "' was provided";
+ } break;
+ }
+ ERR_EXPLAIN("Invalid GDScript waring code: " + get_name_from_code(code));
+ ERR_FAIL_V(String());
+
+#undef CHECK_SYMBOLS
+}
+
+String GDScriptWarning::get_name() const {
+ return get_name_from_code(code);
+}
+
+String GDScriptWarning::get_name_from_code(Code p_code) {
+ ERR_FAIL_COND_V(p_code < 0 || p_code >= WARNING_MAX, String());
+
+ static const char *names[] = {
+ "UNASSIGNED_VARIABLE",
+ "UNASSIGNED_VARIABLE_OP_ASSIGN",
+ "UNUSED_VARIABLE",
+ "UNUSED_CLASS_VARIABLE",
+ "UNUSED_ARGUMENT",
+ "UNREACHABLE_CODE",
+ "STANDALONE_EXPRESSION",
+ "VOID_ASSIGNMENT",
+ "NARROWING_CONVERSION",
+ "FUNCTION_MAY_YIELD",
+ "VARIABLE_CONFLICTS_FUNCTION",
+ "FUNCTION_CONFLICTS_VARIABLE",
+ "FUNCTION_CONFLICTS_CONSTANT",
+ "INCOMPATIBLE_TERNARY",
+ "UNUSED_SIGNAL",
+ "RETURN_VALUE_DISCARDED",
+ "PROPERTY_USED_AS_FUNCTION",
+ "CONSTANT_USED_AS_FUNCTION",
+ "FUNCTION_USED_AS_PROPERTY",
+ "INTEGER_DIVISION",
+ "UNSAFE_PROPERTY_ACCESS",
+ "UNSAFE_METHOD_ACCESS",
+ "UNSAFE_CAST",
+ "UNSAFE_CALL_ARGUMENT",
+ NULL
+ };
+
+ return names[(int)p_code];
+}
+
+GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) {
+ for (int i = 0; i < WARNING_MAX; i++) {
+ if (get_name_from_code((Code)i) == p_name) {
+ return (Code)i;
+ }
+ }
+
+ ERR_EXPLAIN("Invalid GDScript waring name: " + p_name);
+ ERR_FAIL_V(WARNING_MAX);
+}
+
+#endif // DEBUG_ENABLED
+
GDScriptLanguage::GDScriptLanguage() {
calls = 0;
@@ -1903,6 +2056,15 @@ GDScriptLanguage::GDScriptLanguage() {
_debug_max_call_stack = 0;
_call_stack = NULL;
}
+
+#ifdef DEBUG_ENABLED
+ GLOBAL_DEF("debug/gdscript/warnings/enable", true);
+ GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
+ for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
+ String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
+ GLOBAL_DEF("debug/gdscript/warnings/" + warning, !warning.begins_with("unsafe_"));
+ }
+#endif // DEBUG_ENABLED
}
GDScriptLanguage::~GDScriptLanguage() {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 79ac9ed413..d400230f43 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -171,6 +171,7 @@ public:
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 PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this);
virtual bool instance_has(const Object *p_this) const;
virtual bool has_source_code() const;
@@ -261,6 +262,49 @@ public:
~GDScriptInstance();
};
+#ifdef DEBUG_ENABLED
+struct GDScriptWarning {
+ enum Code {
+ UNASSIGNED_VARIABLE, // Variable used but never assigned
+ UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc)
+ UNUSED_VARIABLE, // Local variable is declared but never used
+ UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file
+ UNUSED_ARGUMENT, // Function argument is never used
+ UNREACHABLE_CODE, // Code after a return statement
+ STANDALONE_EXPRESSION, // Expression not assigned to a variable
+ VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable
+ NARROWING_CONVERSION, // Float value into an integer slot, precision is lost
+ FUNCTION_MAY_YIELD, // Typed assign of function call that yields (it may return a function state)
+ VARIABLE_CONFLICTS_FUNCTION, // Variable has the same name of a function
+ FUNCTION_CONFLICTS_VARIABLE, // Function has the same name of a variable
+ FUNCTION_CONFLICTS_CONSTANT, // Function has the same name of a constant
+ INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible
+ UNUSED_SIGNAL, // Signal is defined but never emitted
+ RETURN_VALUE_DISCARDED, // Function call returns something but the value isn't used
+ PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name
+ CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name
+ FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name
+ INTEGER_DIVISION, // Integer divide by integer, decimal part is discarded
+ UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes)
+ UNSAFE_METHOD_ACCESS, // Fucntion not found in the detected type (but can be in subtypes)
+ UNSAFE_CAST, // Cast used in an unknown type
+ UNSAFE_CALL_ARGUMENT, // Function call argument is of a supertype of the require argument
+ WARNING_MAX,
+ } code;
+ Vector<String> symbols;
+ int line;
+
+ String get_name() const;
+ String get_message() const;
+ static String get_name_from_code(Code p_code);
+ static Code get_code_from_name(const String &p_name);
+
+ GDScriptWarning() :
+ line(-1),
+ code(WARNING_MAX) {}
+};
+#endif // DEBUG_ENABLED
+
class GDScriptLanguage : public ScriptLanguage {
static GDScriptLanguage *singleton;
@@ -397,7 +441,7 @@ public:
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);
- 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, Set<int> *r_safe_lines = NULL) 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, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
@@ -448,7 +492,7 @@ public:
/* GLOBAL CLASSES */
virtual bool handles_global_class_type(const String &p_type) const;
- virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const;
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const;
GDScriptLanguage();
~GDScriptLanguage();
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index fe393957db..1403184557 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1009,8 +1009,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
return prev_pos;
int retval = prev_pos;
- //print_line("retval: "+itos(retval));
-
if (retval & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
slevel++;
codegen.alloc_stack(slevel);
@@ -1994,8 +1992,11 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
p_script->_signals[name] = p_class->_signals[i].arguments;
}
- if (!p_class->owner) {
+ if (p_class->owner) {
parsed_classes.insert(p_class->name);
+ if (parsing_classes.has(p_class->name)) {
+ parsing_classes.erase(p_class->name);
+ }
}
//parse sub-classes
@@ -2011,7 +2012,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
Error err = _parse_class_level(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state);
if (err)
return err;
- parsing_classes.erase(name);
}
#ifdef TOOLS_ENABLED
@@ -2071,8 +2071,6 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
//validate instances if keeping state
if (p_keep_state) {
-
- print_line("RELOAD KEEP " + p_script->path);
for (Set<Object *>::Element *E = p_script->instances.front(); E;) {
Set<Object *>::Element *N = E->next();
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 2a42524ba7..30400f01e9 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -46,12 +46,12 @@
void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("#");
- p_delimiters->push_back("\"\"\" \"\"\"");
}
void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("\" \"");
p_delimiters->push_back("' '");
+ p_delimiters->push_back("\"\"\" \"\"\"");
}
Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
#ifdef TOOLS_ENABLED
@@ -116,11 +116,24 @@ void GDScriptLanguage::make_template(const String &p_class_name, const String &p
p_script->set_source_code(src);
}
-bool GDScriptLanguage::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, Set<int> *r_safe_lines) const {
+bool GDScriptLanguage::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, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
GDScriptParser parser;
Error err = parser.parse(p_script, p_path.get_base_dir(), true, p_path, false, r_safe_lines);
+#ifdef DEBUG_ENABLED
+ if (r_warnings) {
+ for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) {
+ const GDScriptWarning &warn = E->get();
+ ScriptLanguage::Warning w;
+ w.line = warn.line;
+ w.code = (int)warn.code;
+ w.string_code = GDScriptWarning::get_name_from_code(warn.code);
+ w.message = warn.get_message();
+ r_warnings->push_back(w);
+ }
+ }
+#endif
if (err) {
r_line_error = parser.get_error_line();
r_col_error = parser.get_error_column();
@@ -179,7 +192,6 @@ int GDScriptLanguage::find_function(const String &p_function, const String &p_co
if (tokenizer.get_token() == GDScriptTokenizer::TK_NEWLINE) {
indent = tokenizer.get_token_line_indent();
}
- //print_line("TOKEN: "+String(GDScriptTokenizer::get_token_name(tokenizer.get_token())));
if (indent == 0 && tokenizer.get_token() == GDScriptTokenizer::TK_PR_FUNCTION && tokenizer.get_token(1) == GDScriptTokenizer::TK_IDENTIFIER) {
String identifier = tokenizer.get_token_identifier(1);
@@ -188,7 +200,6 @@ int GDScriptLanguage::find_function(const String &p_function, const String &p_co
}
}
tokenizer.advance();
- //print_line("NEXT: "+String(GDScriptTokenizer::get_token_name(tokenizer.get_token())));
}
return -1;
}
@@ -2442,7 +2453,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
} break;
case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
List<StringName> constants;
- Variant::get_numeric_constants_for_type(parser.get_completion_built_in_constant(), &constants);
+ Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants);
for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
options.insert(E->get().operator String());
}
@@ -2917,7 +2928,6 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t
break;
}
- //print_line(itos(indent_stack.size())+","+itos(tc)+": "+l);
lines.write[i] = l;
}
@@ -3065,7 +3075,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
case GDScriptParser::DataType::BUILTIN: {
base_type.has_type = false;
- if (Variant::has_numeric_constant(base_type.builtin_type, p_symbol)) {
+ if (Variant::has_constant(base_type.builtin_type, p_symbol)) {
r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
r_result.class_name = Variant::get_type_name(base_type.builtin_type);
r_result.class_member = p_symbol;
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index f2e52d48dd..d9c20868bd 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -642,7 +642,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
str += p_args[i]->operator String();
}
- //str+="\n";
print_line(str);
r_ret = Variant();
@@ -657,7 +656,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
str += p_args[i]->operator String();
}
- //str+="\n";
print_line(str);
r_ret = Variant();
@@ -672,7 +670,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
str += p_args[i]->operator String();
}
- //str+="\n";
print_line(str);
r_ret = Variant();
@@ -686,7 +683,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
str += p_args[i]->operator String();
}
- //str+="\n";
print_error(str);
r_ret = Variant();
@@ -698,7 +694,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
str += p_args[i]->operator String();
}
- //str+="\n";
OS::get_singleton()->print("%s", str.utf8().get_data());
r_ret = Variant();
@@ -716,7 +711,6 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
str += "At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)); // + " in function '" + script->debug_get_stack_level_function(0) + "'";
}
- //str+="\n";
print_line(str);
r_ret = Variant();
} break;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 852d465206..a3f5e1819e 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -38,6 +38,7 @@
#include "io/resource_loader.h"
#include "os/file_access.h"
#include "print_string.h"
+#include "project_settings.h"
#include "script_language.h"
template <class T>
@@ -56,6 +57,8 @@ T *GDScriptParser::alloc_node() {
return t;
}
+static String _find_function_name(const GDScriptParser::OperatorNode *p_call);
+
bool GDScriptParser::_end_statement() {
if (tokenizer->get_token() == GDScriptTokenizer::TK_SEMICOLON) {
@@ -607,7 +610,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
_set_error("Built-in type constant or static function expected after '.'");
return NULL;
}
- if (!Variant::has_numeric_constant(bi_type, identifier)) {
+ if (!Variant::has_constant(bi_type, identifier)) {
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN &&
Variant::is_method_const(bi_type, identifier) &&
@@ -642,7 +645,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
} else {
ConstantNode *cn = alloc_node<ConstantNode>();
- cn->value = Variant::get_numeric_constant_value(bi_type, identifier);
+ cn->value = Variant::get_constant_value(bi_type, identifier);
cn->datatype = _type_from_variant(cn->value);
expr = cn;
}
@@ -726,7 +729,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
BlockNode *b = current_block;
- while (b) {
+ while (!bfn && b) {
if (b->variables.has(identifier)) {
IdentifierNode *id = alloc_node<IdentifierNode>();
LocalVarNode *lv = b->variables[identifier];
@@ -736,6 +739,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
expr = id;
bfn = true;
+#ifdef DEBUG_ENABLED
switch (tokenizer->get_token()) {
case GDScriptTokenizer::TK_OP_ASSIGN_ADD:
case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND:
@@ -747,15 +751,23 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT:
case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT:
case GDScriptTokenizer::TK_OP_ASSIGN_SUB: {
- if (lv->assignments == 0 && !lv->datatype.has_type) {
- _set_error("Using assignment with operation on a variable that was never assigned.");
- return NULL;
+ if (lv->assignments == 0) {
+ if (!lv->datatype.has_type) {
+ _set_error("Using assignment with operation on a variable that was never assigned.");
+ return NULL;
+ }
+ _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String());
}
} // fallthrough
case GDScriptTokenizer::TK_OP_ASSIGN: {
lv->assignments += 1;
+ lv->usages--; // Assignment is not really usage
+ } break;
+ default: {
+ lv->usages++;
}
}
+#endif // DEBUG_ENABLED
break;
}
b = b->parent_block;
@@ -785,6 +797,32 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
if (!bfn) {
+#ifdef DEBUG_ENABLED
+ if (current_function) {
+ int arg_idx = current_function->arguments.find(identifier);
+ if (arg_idx != -1) {
+ switch (tokenizer->get_token()) {
+ case GDScriptTokenizer::TK_OP_ASSIGN_ADD:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR:
+ case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR:
+ case GDScriptTokenizer::TK_OP_ASSIGN_DIV:
+ case GDScriptTokenizer::TK_OP_ASSIGN_MOD:
+ case GDScriptTokenizer::TK_OP_ASSIGN_MUL:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT:
+ case GDScriptTokenizer::TK_OP_ASSIGN_SUB:
+ case GDScriptTokenizer::TK_OP_ASSIGN: {
+ // Assignment is not really usage
+ current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] - 1;
+ } break;
+ default: {
+ current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] + 1;
+ }
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
IdentifierNode *id = alloc_node<IdentifierNode>();
id->name = identifier;
id->line = id_line;
@@ -1036,9 +1074,6 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
} else {
//find list [ or find dictionary {
-
- //print_line("found bug?");
-
_set_error("Error parsing expression, misplaced: " + String(tokenizer->get_token_name(tokenizer->get_token())));
return NULL; //nothing
}
@@ -1986,12 +2021,20 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
// bind
case GDScriptTokenizer::TK_PR_VAR: {
tokenizer->advance();
+ if (!tokenizer->is_token_literal()) {
+ _set_error("Expected identifier for binding variable name.");
+ return NULL;
+ }
pattern->pt_type = GDScriptParser::PatternNode::PT_BIND;
pattern->bind = tokenizer->get_token_identifier();
- // Check if binding is already used
- if (current_block->variables.has(pattern->bind)) {
- _set_error("Binding name of '" + pattern->bind.operator String() + "' was already used in the pattern.");
- return NULL;
+ // Check if variable name is already used
+ BlockNode *bl = current_block;
+ while (bl) {
+ if (bl->variables.has(pattern->bind)) {
+ _set_error("Binding name of '" + pattern->bind.operator String() + "' is already declared in this scope.");
+ return NULL;
+ }
+ bl = bl->parent_block;
}
// Create local variable for proper identifier detection later
LocalVarNode *lv = alloc_node<LocalVarNode>();
@@ -2601,6 +2644,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
pending_newline = -1;
}
+#ifdef DEBUG_ENABLED
switch (token) {
case GDScriptTokenizer::TK_EOF:
case GDScriptTokenizer::TK_ERROR:
@@ -2609,13 +2653,13 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
// will check later
} break;
default: {
- // TODO: Make this a warning
- /*if (p_block->has_return) {
- _set_error("Unreacheable code.");
- return;
- }*/
+ if (p_block->has_return && !current_function->has_unreachable_code) {
+ _add_warning(GDScriptWarning::UNREACHABLE_CODE, -1, current_function->name.operator String());
+ current_function->has_unreachable_code = true;
+ }
} break;
}
+#endif // DEBUG_ENABLED
switch (token) {
case GDScriptTokenizer::TK_EOF:
p_block->end_line = tokenizer->get_token_line();
@@ -2728,6 +2772,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
c->line = var_line;
assigned = c;
}
+ lv->assign = assigned;
//must be added later, to avoid self-referencing.
p_block->variables.insert(n, lv);
@@ -2745,6 +2790,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
lv->assign_op = op;
lv->assign = assigned;
+ lv->assign_op = op;
+
if (!_end_statement()) {
_set_error("Expected end of statement (var)");
return;
@@ -3387,6 +3434,32 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
tokenizer->advance(2);
+ if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) {
+ tokenizer->advance();
+
+ if ((tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type() == Variant::STRING)) {
+ Variant constant = tokenizer->get_token_constant();
+ String icon_path = constant.operator String();
+
+ String abs_icon_path = icon_path.is_rel_path() ? self_path.get_base_dir().plus_file(icon_path).simplify_path() : icon_path;
+ if (!FileAccess::exists(abs_icon_path)) {
+ _set_error("No class icon found at: " + abs_icon_path);
+ return;
+ }
+
+ p_class->icon_path = icon_path;
+
+ tokenizer->advance();
+ } else {
+ _set_error("Optional parameter after 'class_name' must be a string constant file path to an icon.");
+ return;
+ }
+
+ } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONSTANT) {
+ _set_error("Class icon must be separated by a comma.");
+ return;
+ }
+
} break;
case GDScriptTokenizer::TK_PR_TOOL: {
@@ -3513,6 +3586,17 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
}
}
+#ifdef DEBUG_ENABLED
+ if (p_class->constant_expressions.has(name)) {
+ _add_warning(GDScriptWarning::FUNCTION_CONFLICTS_CONSTANT, -1, name);
+ }
+ for (int i = 0; i < p_class->variables.size(); i++) {
+ if (p_class->variables[i].identifier == name) {
+ _add_warning(GDScriptWarning::FUNCTION_CONFLICTS_VARIABLE, -1, name);
+ }
+ }
+#endif // DEBUG_ENABLED
+
if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
_set_error("Expected '(' after identifier (syntax: 'func <identifier>([arguments]):' ).");
@@ -3524,6 +3608,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
Vector<StringName> arguments;
Vector<DataType> argument_types;
Vector<Node *> default_values;
+#ifdef DEBUG_ENABLED
+ Vector<int> arguments_usage;
+#endif // DEBUG_ENABLED
int fnline = tokenizer->get_token_line();
@@ -3550,6 +3637,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
StringName argname = tokenizer->get_token_identifier();
arguments.push_back(argname);
+#ifdef DEBUG_ENABLED
+ arguments_usage.push_back(0);
+#endif // DEBUG_ENABLED
tokenizer->advance();
@@ -3703,7 +3793,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
function->default_values = default_values;
function->_static = _static;
function->line = fnline;
-
+#ifdef DEBUG_ENABLED
+ function->arguments_usage = arguments_usage;
+#endif // DEBUG_ENABLED
function->rpc_mode = rpc_mode;
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
@@ -3730,6 +3822,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
ClassNode::Signal sig;
sig.name = tokenizer->get_token_identifier();
+ sig.emissions = 0;
+ sig.line = tokenizer->get_token_line();
tokenizer->advance();
if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) {
@@ -4413,6 +4507,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
member.expression = NULL;
member._export.name = member.identifier;
member.line = tokenizer->get_token_line();
+ member.usages = 0;
member.rpc_mode = rpc_mode;
if (current_class->constant_expressions.has(member.identifier)) {
@@ -4428,7 +4523,20 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
}
-
+#ifdef DEBUG_ENABLED
+ for (int i = 0; i < current_class->functions.size(); i++) {
+ if (current_class->functions[i]->name == member.identifier) {
+ _add_warning(GDScriptWarning::VARIABLE_CONFLICTS_FUNCTION, member.line, member.identifier);
+ break;
+ }
+ }
+ for (int i = 0; i < current_class->static_functions.size(); i++) {
+ if (current_class->static_functions[i]->name == member.identifier) {
+ _add_warning(GDScriptWarning::VARIABLE_CONFLICTS_FUNCTION, member.line, member.identifier);
+ break;
+ }
+ }
+#endif // DEBUG_ENABLED
tokenizer->advance();
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
@@ -5689,11 +5797,26 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
node_type.has_type = true;
node_type.kind = DataType::BUILTIN;
node_type.builtin_type = Variant::ARRAY;
+#ifdef DEBUG_ENABLED
+ // Check stuff inside the array
+ ArrayNode *an = static_cast<ArrayNode *>(p_node);
+ for (int i = 0; i < an->elements.size(); i++) {
+ _reduce_node_type(an->elements[i]);
+ }
+#endif // DEBUG_ENABLED
} break;
case Node::TYPE_DICTIONARY: {
node_type.has_type = true;
node_type.kind = DataType::BUILTIN;
node_type.builtin_type = Variant::DICTIONARY;
+#ifdef DEBUG_ENABLED
+ // Check stuff inside the dictionarty
+ DictionaryNode *dn = static_cast<DictionaryNode *>(p_node);
+ for (int i = 0; i < dn->elements.size(); i++) {
+ _reduce_node_type(dn->elements[i].key);
+ _reduce_node_type(dn->elements[i].value);
+ }
+#endif // DEBUG_ENABLED
} break;
case Node::TYPE_SELF: {
node_type.has_type = true;
@@ -5704,6 +5827,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
IdentifierNode *id = static_cast<IdentifierNode *>(p_node);
if (id->declared_block) {
node_type = id->declared_block->variables[id->name]->get_datatype();
+ id->declared_block->variables[id->name]->usages += 1;
} else if (id->name == "#match_value") {
// It's a special id just for the match statetement, ignore
break;
@@ -5738,6 +5862,9 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
}
}
} else {
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::UNSAFE_CAST, cn->line, cn->cast_type.to_string());
+#endif // DEBUG_ENABLED
_mark_line_as_unsafe(cn->line);
}
@@ -5864,6 +5991,12 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
op->line, op->column);
return DataType();
}
+#ifdef DEBUG_ENABLED
+ if (var_op == Variant::OP_DIVIDE && argument_a_type.has_type && argument_a_type.kind == DataType::BUILTIN && argument_a_type.builtin_type == Variant::INT &&
+ argument_b_type.has_type && argument_b_type.kind == DataType::BUILTIN && argument_b_type.builtin_type == Variant::INT) {
+ _add_warning(GDScriptWarning::INTEGER_DIVISION, op->line);
+ }
+#endif // DEBUG_ENABLED
} break;
// Ternary operators
@@ -5882,10 +6015,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
node_type = true_type;
} else if (_is_type_compatible(false_type, true_type)) {
node_type = false_type;
+ } else {
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::INCOMPATIBLE_TERNARY, op->line);
+#endif // DEBUG_ENABLED
}
-
- // TODO: Warn if types aren't compatible
-
} break;
// Assignment should never happen within an expression
case OperatorNode::OP_ASSIGN:
@@ -5948,6 +6082,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
node_type = result;
} else {
node_type = _reduce_identifier_type(&base_type, member_id->name, op->line);
+#ifdef DEBUG_ENABLED
+ if (!node_type.has_type) {
+ _add_warning(GDScriptWarning::UNSAFE_PROPERTY_ACCESS, op->line, member_id->name.operator String(), base_type.to_string());
+ }
+#endif // DEBUG_ENABLED
}
} else {
_mark_line_as_unsafe(op->line);
@@ -6367,6 +6506,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
if (!_is_type_compatible(arg_type, par_types[i], true)) {
types_match = false;
break;
+ } else {
+#ifdef DEBUG_ENABLED
+ if (arg_type.kind == DataType::BUILTIN && arg_type.builtin_type == Variant::INT && par_types[i].kind == DataType::BUILTIN && par_types[i].builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, p_call->line, Variant::get_type_name(tn->vtype));
+ }
+ if (par_types[i].may_yield && p_call->arguments[i + 1]->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i + 1])));
+ }
+#endif // DEBUG_ENABLED
}
}
@@ -6400,6 +6548,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
return_type = _type_from_property(mi.return_val, false);
+#ifdef DEBUG_ENABLED
+ // Check all arguments beforehand to solve warnings
+ for (int i = 1; i < p_call->arguments.size(); i++) {
+ _reduce_node_type(p_call->arguments[i]);
+ }
+#endif // DEBUG_ENABLED
+
// Check arguments
is_vararg = mi.flags & METHOD_FLAG_VARARG;
@@ -6426,6 +6581,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
ERR_FAIL_V(DataType());
}
+#ifdef DEBUG_ENABLED
+ // Check all arguments beforehand to solve warnings
+ for (int i = arg_id + 1; i < p_call->arguments.size(); i++) {
+ _reduce_node_type(p_call->arguments[i]);
+ }
+#endif // DEBUG_ENABLED
+
IdentifierNode *func_id = static_cast<IdentifierNode *>(p_call->arguments[arg_id]);
callee_name = func_id->name;
arg_count -= 1 + arg_id;
@@ -6505,8 +6667,18 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
_set_error("Method '" + callee_name + "' is not declared in the current class.", p_call->line);
return DataType();
}
+ DataType tmp_type;
+ valid = _get_member_type(original_type, func_id->name, tmp_type);
+ if (valid) {
+ if (tmp_type.is_constant) {
+ _add_warning(GDScriptWarning::CONSTANT_USED_AS_FUNCTION, p_call->line, callee_name, original_type.to_string());
+ } else {
+ _add_warning(GDScriptWarning::PROPERTY_USED_AS_FUNCTION, p_call->line, callee_name, original_type.to_string());
+ }
+ }
+ _add_warning(GDScriptWarning::UNSAFE_METHOD_ACCESS, p_call->line, callee_name, original_type.to_string());
_mark_line_as_unsafe(p_call->line);
-#endif
+#endif // DEBUG_ENABLED
return DataType();
}
@@ -6522,7 +6694,19 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
_set_error("Non-static function '" + String(callee_name) + "' can only be called from an instance.", p_call->line);
return DataType();
}
-#endif
+
+ // Check signal emission for warnings
+ if (callee_name == "emit_signal" && p_call->op == OperatorNode::OP_CALL && p_call->arguments[0]->type == Node::TYPE_SELF && p_call->arguments.size() >= 3 && p_call->arguments[2]->type == Node::TYPE_CONSTANT) {
+ ConstantNode *sig = static_cast<ConstantNode *>(p_call->arguments[2]);
+ String emitted = sig->value.get_type() == Variant::STRING ? sig->value.operator String() : "";
+ for (int i = 0; i < current_class->_signals.size(); i++) {
+ if (current_class->_signals[i].name == emitted) {
+ current_class->_signals.write[i].emissions += 1;
+ break;
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
} break;
}
@@ -6547,8 +6731,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
continue;
}
+ DataType arg_type = arg_types[i - arg_diff];
+
if (!par_type.has_type) {
_mark_line_as_unsafe(p_call->line);
+#ifdef DEBUG_ENABLED
+ if (par_type.may_yield && p_call->arguments[i]->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i])));
+ }
+#endif // DEBUG_ENABLED
} else if (!_is_type_compatible(arg_types[i - arg_diff], par_type, true)) {
// Supertypes are acceptable for dynamic compliance
if (!_is_type_compatible(par_type, arg_types[i - arg_diff])) {
@@ -6560,6 +6751,12 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
} else {
_mark_line_as_unsafe(p_call->line);
}
+ } else {
+#ifdef DEBUG_ENABLED
+ if (arg_type.kind == DataType::BUILTIN && arg_type.builtin_type == Variant::INT && par_type.kind == DataType::BUILTIN && par_type.builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, p_call->line, callee_name);
+ }
+#endif // DEBUG_ENABLED
}
}
@@ -6795,6 +6992,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
DataType member_type;
+ for (int i = 0; i < current_class->variables.size(); i++) {
+ ClassNode::Member m = current_class->variables[i];
+ if (current_class->variables[i].identifier == p_identifier) {
+ member_type = current_class->variables[i].data_type;
+ current_class->variables.write[i].usages += 1;
+ return member_type;
+ }
+ }
+
if (_get_member_type(base_type, p_identifier, member_type)) {
return member_type;
}
@@ -6922,6 +7128,19 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
_set_error("Identifier '" + p_identifier.operator String() + "' is not declared in the current scope.", p_line);
}
+#ifdef DEBUG_ENABLED
+ {
+ DataType tmp_type;
+ List<DataType> arg_types;
+ int argcount;
+ bool _static;
+ bool vararg;
+ if (_get_function_signature(base_type, p_identifier, tmp_type, arg_types, argcount, _static, vararg)) {
+ _add_warning(GDScriptWarning::FUNCTION_USED_AS_PROPERTY, p_line, p_identifier.operator String(), base_type.to_string());
+ }
+ }
+#endif // DEBUG_ENABLED
+
_mark_line_as_unsafe(p_line);
return DataType();
}
@@ -7174,6 +7393,11 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
}
}
}
+#ifdef DEBUG_ENABLED
+ if (p_function->arguments_usage[i] == 0 && !p_function->arguments[i].operator String().begins_with("_")) {
+ _add_warning(GDScriptWarning::UNUSED_ARGUMENT, p_function->line, p_function->name, p_function->arguments[i].operator String());
+ }
+#endif // DEBUG_ENABLED
}
if (!(p_function->name == "_init")) {
@@ -7244,6 +7468,7 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
if (p_function->has_yield) {
// yield() will make the function return a GDScriptFunctionState, so the type is ambiguous
p_function->return_type.has_type = false;
+ p_function->return_type.may_yield = true;
}
}
@@ -7270,6 +7495,20 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
if (error_set) return;
}
+#ifdef DEBUG_ENABLED
+ // Warnings
+ for (int i = 0; i < p_class->variables.size(); i++) {
+ if (p_class->variables[i].usages == 0) {
+ _add_warning(GDScriptWarning::UNUSED_CLASS_VARIABLE, p_class->variables[i].line, p_class->variables[i].identifier);
+ }
+ }
+ for (int i = 0; i < p_class->_signals.size(); i++) {
+ if (p_class->_signals[i].emissions == 0) {
+ _add_warning(GDScriptWarning::UNUSED_SIGNAL, p_class->_signals[i].line, p_class->_signals[i].name);
+ }
+ }
+#endif // DEBUG_ENABLED
+
// Inner classes
for (int i = 0; i < p_class->subclasses.size(); i++) {
current_class = p_class->subclasses[i];
@@ -7279,6 +7518,26 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) {
}
}
+#ifdef DEBUG_ENABLED
+static String _find_function_name(const GDScriptParser::OperatorNode *p_call) {
+ switch (p_call->arguments[0]->type) {
+ case GDScriptParser::Node::TYPE_TYPE: {
+ return Variant::get_type_name(static_cast<GDScriptParser::TypeNode *>(p_call->arguments[0])->vtype);
+ } break;
+ case GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION: {
+ return GDScriptFunctions::get_func_name(static_cast<GDScriptParser::BuiltInFunctionNode *>(p_call->arguments[0])->function);
+ } break;
+ default: {
+ int id_index = p_call->op == GDScriptParser::OperatorNode::OP_PARENT_CALL ? 0 : 1;
+ if (p_call->arguments.size() > id_index && p_call->arguments[id_index]->type == GDScriptParser::Node::TYPE_IDENTIFIER) {
+ return static_cast<GDScriptParser::IdentifierNode *>(p_call->arguments[id_index])->name;
+ }
+ } break;
+ }
+ return String();
+}
+#endif // DEBUG_ENABLED
+
void GDScriptParser::_check_block_types(BlockNode *p_block) {
Node *last_var_assign = NULL;
@@ -7297,8 +7556,23 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
lv->datatype = _resolve_type(lv->datatype, lv->line);
_mark_line_as_safe(lv->line);
+ last_var_assign = lv->assign;
if (lv->assign) {
DataType assign_type = _reduce_node_type(lv->assign);
+#ifdef DEBUG_ENABLED
+ if (assign_type.has_type && assign_type.kind == DataType::BUILTIN && assign_type.builtin_type == Variant::NIL) {
+ if (lv->assign->type == Node::TYPE_OPERATOR) {
+ OperatorNode *call = static_cast<OperatorNode *>(lv->assign);
+ if (call->op == OperatorNode::OP_CALL || call->op == OperatorNode::OP_PARENT_CALL) {
+ _add_warning(GDScriptWarning::VOID_ASSIGNMENT, lv->line, _find_function_name(call));
+ }
+ }
+ }
+ if (lv->datatype.has_type && assign_type.may_yield && lv->assign->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, lv->line, _find_function_name(static_cast<OperatorNode *>(lv->assign)));
+ }
+#endif // DEBUG_ENABLED
+
if (!_is_type_compatible(lv->datatype, assign_type)) {
// Try supertype test
if (_is_type_compatible(assign_type, lv->datatype)) {
@@ -7329,6 +7603,11 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
lv->assign = convert_call;
lv->assign_op->arguments.write[1] = convert_call;
+#ifdef DEBUG_ENABLED
+ if (lv->datatype.builtin_type == Variant::INT && assign_type.builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, lv->line);
+ }
+#endif // DEBUG_ENABLED
}
}
if (lv->datatype.infer_type) {
@@ -7343,15 +7622,6 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
_mark_line_as_unsafe(lv->line);
}
}
- last_var_assign = lv->assign;
-
- // TODO: Make a warning
- /*
- if (lv->assignments == 0) {
- _set_error("Variable '" + String(lv->name) + "' is never assigned.", lv->line);
- return;
- }
- */
} break;
case Node::TYPE_OPERATOR: {
OperatorNode *op = static_cast<OperatorNode *>(statement);
@@ -7417,6 +7687,19 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
} else {
rh_type = _reduce_node_type(op->arguments[1]);
}
+#ifdef DEBUG_ENABLED
+ if (rh_type.has_type && rh_type.kind == DataType::BUILTIN && rh_type.builtin_type == Variant::NIL) {
+ if (op->arguments[1]->type == Node::TYPE_OPERATOR) {
+ OperatorNode *call = static_cast<OperatorNode *>(op->arguments[1]);
+ if (call->op == OperatorNode::OP_CALL || call->op == OperatorNode::OP_PARENT_CALL) {
+ _add_warning(GDScriptWarning::VOID_ASSIGNMENT, op->line, _find_function_name(call));
+ }
+ }
+ }
+ if (lh_type.has_type && rh_type.may_yield && op->arguments[1]->type == Node::TYPE_OPERATOR) {
+ _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, op->line, _find_function_name(static_cast<OperatorNode *>(op->arguments[1])));
+ }
+#endif // DEBUG_ENABLED
if (!_is_type_compatible(lh_type, rh_type)) {
// Try supertype test
@@ -7447,6 +7730,11 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
convert_call->arguments.push_back(tgt_type);
op->arguments.write[1] = convert_call;
+#ifdef DEBUG_ENABLED
+ if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) {
+ _add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line);
+ }
+#endif // DEBUG_ENABLED
}
}
if (!rh_type.has_type && (op->op != OperatorNode::OP_ASSIGN || lh_type.has_type || op->arguments[0]->type == Node::TYPE_OPERATOR)) {
@@ -7456,15 +7744,29 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
case OperatorNode::OP_CALL:
case OperatorNode::OP_PARENT_CALL: {
_mark_line_as_safe(op->line);
- _reduce_function_call_type(op);
+ DataType func_type = _reduce_function_call_type(op);
+#ifdef DEBUG_ENABLED
+ if (func_type.has_type && (func_type.kind != DataType::BUILTIN || func_type.builtin_type != Variant::NIL)) {
+ // Figure out function name for warning
+ String func_name = _find_function_name(op);
+ if (func_name.empty()) {
+ func_name == "<undetected name>";
+ }
+ _add_warning(GDScriptWarning::RETURN_VALUE_DISCARDED, op->line, func_name);
+ }
+#endif // DEBUG_ENABLED
if (error_set) return;
} break;
+ case OperatorNode::OP_YIELD: {
+ _mark_line_as_safe(op->line);
+ _reduce_node_type(op);
+ } break;
default: {
_mark_line_as_safe(op->line);
_reduce_node_type(op); // Test for safety anyway
- // TODO: Make this a warning
- /*_set_error("Standalone expression, nothing is done in this line.", statement->line);
- return; */
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::STANDALONE_EXPRESSION, statement->line);
+#endif // DEBUG_ENABLED
}
}
} break;
@@ -7531,9 +7833,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
default: {
_mark_line_as_safe(statement->line);
_reduce_node_type(statement); // Test for safety anyway
- // TODO: Make this a warning
- /* _set_error("Standalone expression, nothing is done in this line.", statement->line);
- return; */
+#ifdef DEBUG_ENABLED
+ _add_warning(GDScriptWarning::STANDALONE_EXPRESSION, statement->line);
+#endif // DEBUG_ENABLED
}
}
}
@@ -7545,6 +7847,20 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
current_block = p_block;
if (error_set) return;
}
+
+#ifdef DEBUG_ENABLED
+ // Warnings check
+ for (Map<StringName, LocalVarNode *>::Element *E = p_block->variables.front(); E; E = E->next()) {
+ LocalVarNode *lv = E->get();
+ if (!lv->name.operator String().begins_with("_")) {
+ if (lv->usages == 0) {
+ _add_warning(GDScriptWarning::UNUSED_VARIABLE, lv->line, lv->name);
+ } else if (lv->assignments == 0) {
+ _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE, lv->line, lv->name);
+ }
+ }
+ }
+#endif // DEBUG_ENABLED
}
void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) {
@@ -7558,6 +7874,56 @@ void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column)
error_set = true;
}
+#ifdef DEBUG_ENABLED
+void GDScriptParser::_add_warning(int p_code, int p_line, const String &p_symbol1, const String &p_symbol2, const String &p_symbol3, const String &p_symbol4) {
+ Vector<String> symbols;
+ if (!p_symbol1.empty()) {
+ symbols.push_back(p_symbol1);
+ }
+ if (!p_symbol2.empty()) {
+ symbols.push_back(p_symbol2);
+ }
+ if (!p_symbol3.empty()) {
+ symbols.push_back(p_symbol3);
+ }
+ if (!p_symbol4.empty()) {
+ symbols.push_back(p_symbol4);
+ }
+ _add_warning(p_code, p_line, symbols);
+}
+
+void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> &p_symbols) {
+ if (tokenizer->is_ignoring_warnings() || !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize()) {
+ return;
+ }
+ String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower();
+ if (tokenizer->get_warning_global_skips().has(warn_name)) {
+ return;
+ }
+ if (!GLOBAL_GET("debug/gdscript/warnings/" + warn_name)) {
+ return;
+ }
+
+ GDScriptWarning warn;
+ warn.code = (GDScriptWarning::Code)p_code;
+ warn.symbols = p_symbols;
+ warn.line = p_line == -1 ? tokenizer->get_token_line() : p_line;
+
+ List<GDScriptWarning>::Element *before = NULL;
+ for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) {
+ if (E->get().line > warn.line) {
+ break;
+ }
+ before = E;
+ }
+ if (before) {
+ warnings.insert_after(before, warn);
+ } else {
+ warnings.push_front(warn);
+ }
+}
+#endif // DEBUG_ENABLED
+
String GDScriptParser::get_error() const {
return error;
@@ -7624,6 +7990,37 @@ Error GDScriptParser::_parse(const String &p_base_path) {
return ERR_PARSE_ERROR;
}
+#ifdef DEBUG_ENABLED
+ // Resolve warning ignores
+ Vector<Pair<int, String> > warning_skips = tokenizer->get_warning_skips();
+ bool warning_is_error = GLOBAL_GET("debug/gdscript/warnings/treat_warnings_as_errors").booleanize();
+ for (List<GDScriptWarning>::Element *E = warnings.front(); E;) {
+ GDScriptWarning &w = E->get();
+ int skip_index = -1;
+ for (int i = 0; i < warning_skips.size(); i++) {
+ if (warning_skips[i].first >= w.line) {
+ break;
+ }
+ skip_index = i;
+ }
+ List<GDScriptWarning>::Element *next = E->next();
+ bool erase = false;
+ if (skip_index != -1) {
+ if (warning_skips[skip_index].second == GDScriptWarning::get_name_from_code(w.code).to_lower()) {
+ erase = true;
+ }
+ warning_skips.remove(skip_index);
+ }
+ if (erase) {
+ warnings.erase(E);
+ } else if (warning_is_error) {
+ _set_error(w.get_message() + " (warning treated as error)", w.line);
+ return ERR_PARSE_ERROR;
+ }
+ E = next;
+ }
+#endif // DEBUG_ENABLED
+
return OK;
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 48f256b4c6..dbe523a0b9 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -38,6 +38,7 @@
#include "script_language.h"
struct GDScriptDataType;
+struct GDScriptWarning;
class GDScriptParser {
public:
@@ -57,6 +58,7 @@ public:
bool is_constant;
bool is_meta_type; // Whether the value can be used as a type
bool infer_type;
+ bool may_yield; // For function calls
Variant::Type builtin_type;
StringName native_type;
@@ -95,6 +97,7 @@ public:
is_constant(false),
is_meta_type(false),
infer_type(false),
+ may_yield(false),
builtin_type(Variant::NIL),
class_type(NULL) {}
};
@@ -146,6 +149,7 @@ public:
StringName extends_file;
Vector<StringName> extends_class;
DataType base_type;
+ String icon_path;
struct Member {
PropertyInfo _export;
@@ -160,6 +164,7 @@ public:
Node *expression;
OperatorNode *initial_assignment;
MultiplayerAPI::RPCMode rpc_mode;
+ int usages;
};
struct Constant {
Node *expression;
@@ -169,6 +174,8 @@ public:
struct Signal {
StringName name;
Vector<StringName> arguments;
+ int emissions;
+ int line;
};
Vector<ClassNode *> subclasses;
@@ -197,12 +204,16 @@ public:
bool _static;
MultiplayerAPI::RPCMode rpc_mode;
bool has_yield;
+ bool has_unreachable_code;
StringName name;
DataType return_type;
Vector<StringName> arguments;
Vector<DataType> argument_types;
Vector<Node *> default_values;
BlockNode *body;
+#ifdef DEBUG_ENABLED
+ Vector<int> arguments_usage;
+#endif // DEBUG_ENABLED
virtual DataType get_datatype() const { return return_type; }
virtual void set_datatype(const DataType &p_datatype) { return_type = p_datatype; }
@@ -212,6 +223,7 @@ public:
_static = false;
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
has_yield = false;
+ has_unreachable_code = false;
}
};
@@ -267,6 +279,7 @@ public:
Node *assign;
OperatorNode *assign_op;
int assignments;
+ int usages;
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
@@ -275,6 +288,7 @@ public:
assign = NULL;
assign_op = NULL;
assignments = 0;
+ usages = 0;
}
};
@@ -518,6 +532,10 @@ private:
Set<int> *safe_lines;
#endif // DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
+ List<GDScriptWarning> warnings;
+#endif // DEBUG_ENABLED
+
int pending_newline;
List<int> tab_level;
@@ -550,6 +568,10 @@ private:
MultiplayerAPI::RPCMode rpc_mode;
void _set_error(const String &p_error, int p_line = -1, int p_column = -1);
+#ifdef DEBUG_ENABLED
+ void _add_warning(int p_code, int p_line = -1, const String &p_symbol1 = String(), const String &p_symbol2 = String(), const String &p_symbol3 = String(), const String &p_symbol4 = String());
+ void _add_warning(int p_code, int p_line, const Vector<String> &p_symbols);
+#endif // DEBUG_ENABLED
bool _recover_from_completion();
bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false);
@@ -605,6 +627,9 @@ public:
String get_error() const;
int get_error_line() const;
int get_error_column() const;
+#ifdef DEBUG_ENABLED
+ const List<GDScriptWarning> &get_warnings() const { return warnings; }
+#endif // DEBUG_ENABLED
Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL);
Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = "");
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 7ae7c72ed3..6e7842f190 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -526,8 +526,13 @@ void GDScriptTokenizerText::_advance() {
return;
}
case '#': { // line comment skip
-
+#ifdef DEBUG_ENABLED
+ String comment;
+#endif // DEBUG_ENABLED
while (GETCHAR(0) != '\n') {
+#ifdef DEBUG_ENABLED
+ comment += GETCHAR(0);
+#endif // DEBUG_ENABLED
code_pos++;
if (GETCHAR(0) == 0) { //end of file
//_make_error("Unterminated Comment");
@@ -535,6 +540,17 @@ void GDScriptTokenizerText::_advance() {
return;
}
}
+#ifdef DEBUG_ENABLED
+ if (comment.begins_with("#warning-ignore:")) {
+ String code = comment.get_slice(":", 1);
+ warning_skips.push_back(Pair<int, String>(line, code.strip_edges().to_lower()));
+ } else if (comment.begins_with("#warning-ignore-all:")) {
+ String code = comment.get_slice(":", 1);
+ warning_global_skips.insert(code.strip_edges().to_lower());
+ } else if (comment.strip_edges() == "#warnings-disable") {
+ ignore_warnings = true;
+ }
+#endif // DEBUG_ENABLED
INCPOS(1);
column = 1;
line++;
@@ -921,7 +937,6 @@ void GDScriptTokenizerText::_advance() {
_make_constant(val);
} else if (period_found || exponent_found) {
double val = str.to_double();
- //print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val));
_make_constant(val);
} else {
int64_t val = str.to_int64();
@@ -1045,6 +1060,9 @@ void GDScriptTokenizerText::set_code(const String &p_code) {
column = 1; //the same holds for columns
tk_rb_pos = 0;
error_flag = false;
+#ifdef DEBUG_ENABLED
+ ignore_warnings = false;
+#endif // DEBUG_ENABLED
last_error = "";
for (int i = 0; i < MAX_LOOKAHEAD + 1; i++)
_advance();
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 5bd303224c..11a291cb2e 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -31,6 +31,7 @@
#ifndef GDSCRIPT_TOKENIZER_H
#define GDSCRIPT_TOKENIZER_H
+#include "core/pair.h"
#include "gdscript_functions.h"
#include "string_db.h"
#include "ustring.h"
@@ -171,6 +172,11 @@ public:
virtual int get_token_line_indent(int p_offset = 0) const = 0;
virtual String get_token_error(int p_offset = 0) const = 0;
virtual void advance(int p_amount = 1) = 0;
+#ifdef DEBUG_ENABLED
+ virtual const Vector<Pair<int, String> > &get_warning_skips() const = 0;
+ virtual const Set<String> &get_warning_global_skips() const = 0;
+ virtual const bool is_ignoring_warnings() const = 0;
+#endif // DEBUG_ENABLED
virtual ~GDScriptTokenizer(){};
};
@@ -190,6 +196,7 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
union {
Variant::Type vtype; //for type types
GDScriptFunctions::Function func; //function for built in functions
+ int warning_code; //for warning skip
};
int line, col;
TokenData() {
@@ -217,6 +224,11 @@ class GDScriptTokenizerText : public GDScriptTokenizer {
int tk_rb_pos;
String last_error;
bool error_flag;
+#ifdef DEBUG_ENABLED
+ Vector<Pair<int, String> > warning_skips;
+ Set<String> warning_global_skips;
+ bool ignore_warnings;
+#endif // DEBUG_ENABLED
void _advance();
@@ -232,6 +244,11 @@ public:
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
+#ifdef DEBUG_ENABLED
+ virtual const Vector<Pair<int, String> > &get_warning_skips() const { return warning_skips; }
+ virtual const Set<String> &get_warning_global_skips() const { return warning_global_skips; }
+ virtual const bool is_ignoring_warnings() const { return ignore_warnings; }
+#endif // DEBUG_ENABLED
};
class GDScriptTokenizerBuffer : public GDScriptTokenizer {
@@ -265,6 +282,17 @@ public:
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
+#ifdef DEBUG_ENABLED
+ virtual const Vector<Pair<int, String> > &get_warning_skips() const {
+ static Vector<Pair<int, String> > v;
+ return v;
+ }
+ virtual const Set<String> &get_warning_global_skips() const {
+ static Set<String> s;
+ return s;
+ }
+ virtual const bool is_ignoring_warnings() const { return true; }
+#endif // DEBUG_ENABLED
GDScriptTokenizerBuffer();
};
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 0c5df57d49..776c18da64 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -208,21 +208,35 @@ bool GridMap::get_collision_layer_bit(int p_bit) const {
return get_collision_layer() & (1 << p_bit);
}
+#ifndef DISABLE_DEPRECATED
void GridMap::set_theme(const Ref<MeshLibrary> &p_theme) {
- if (!theme.is_null())
- theme->unregister_owner(this);
- theme = p_theme;
- if (!theme.is_null())
- theme->register_owner(this);
+ WARN_PRINTS("GridMap.theme/set_theme() is deprecated and will be removed in a future version. Use GridMap.mesh_library/set_mesh_library() instead.");
+ set_mesh_library(p_theme);
+}
+
+Ref<MeshLibrary> GridMap::get_theme() const {
+
+ WARN_PRINTS("GridMap.theme/get_theme() is deprecated and will be removed in a future version. Use GridMap.mesh_library/get_mesh_library() instead.");
+ return get_mesh_library();
+}
+#endif // DISABLE_DEPRECATED
+
+void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
+
+ if (!mesh_library.is_null())
+ mesh_library->unregister_owner(this);
+ mesh_library = p_mesh_library;
+ if (!mesh_library.is_null())
+ mesh_library->register_owner(this);
_recreate_octant_data();
- _change_notify("theme");
+ _change_notify("mesh_library");
}
-Ref<MeshLibrary> GridMap::get_theme() const {
+Ref<MeshLibrary> GridMap::get_mesh_library() const {
- return theme;
+ return mesh_library;
}
void GridMap::set_cell_size(const Vector3 &p_size) {
@@ -469,11 +483,9 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
ERR_CONTINUE(!cell_map.has(E->get()));
const Cell &c = cell_map[E->get()];
- if (!theme.is_valid() || !theme->has_item(c.item))
+ if (!mesh_library.is_valid() || !mesh_library->has_item(c.item))
continue;
- //print_line("OCTANT, CELLS: "+itos(ii.cells.size()));
-
Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z);
Vector3 ofs = _get_offset();
@@ -488,7 +500,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
if (baked_meshes.size() == 0) {
- if (theme->get_item_mesh(c.item).is_valid()) {
+ if (mesh_library->get_item_mesh(c.item).is_valid()) {
if (!multimesh_items.has(c.item)) {
multimesh_items[c.item] = List<Pair<Transform, IndexKey> >();
}
@@ -500,7 +512,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
}
- Vector<MeshLibrary::ShapeData> shapes = theme->get_item_shapes(c.item);
+ Vector<MeshLibrary::ShapeData> shapes = mesh_library->get_item_shapes(c.item);
// add the item's shape at given xform to octant's static_body
for (int i = 0; i < shapes.size(); i++) {
// add the item's shape
@@ -510,12 +522,10 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
if (g.collision_debug.is_valid()) {
shapes.write[i].shape->add_vertices_to_array(col_debug, xform * shapes[i].local_transform);
}
-
- //print_line("PHIS x: "+xform);
}
// add the item's navmesh at given xform to GridMap's Navigation ancestor
- Ref<NavigationMesh> navmesh = theme->get_item_navmesh(c.item);
+ Ref<NavigationMesh> navmesh = mesh_library->get_item_navmesh(c.item);
if (navmesh.is_valid()) {
Octant::NavMesh nm;
nm.xform = xform;
@@ -537,7 +547,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
RID mm = VS::get_singleton()->multimesh_create();
VS::get_singleton()->multimesh_allocate(mm, E->get().size(), VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_NONE);
- VS::get_singleton()->multimesh_set_mesh(mm, theme->get_item_mesh(E->key())->get_rid());
+ VS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E->key())->get_rid());
int idx = 0;
for (List<Pair<Transform, IndexKey> >::Element *F = E->get().front(); F; F = F->next()) {
@@ -600,7 +610,6 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
Octant &g = *octant_map[p_key];
PhysicsServer::get_singleton()->body_set_state(g.static_body, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
PhysicsServer::get_singleton()->body_set_space(g.static_body, get_world()->get_space());
- //print_line("BODYPOS: "+get_global_transform());
if (g.collision_debug_instance.is_valid()) {
VS::get_singleton()->instance_set_scenario(g.collision_debug_instance, get_world()->get_scenario());
@@ -612,11 +621,11 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
VS::get_singleton()->instance_set_transform(g.multimesh_instances[i].instance, get_global_transform());
}
- if (navigation && theme.is_valid()) {
+ if (navigation && mesh_library.is_valid()) {
for (Map<IndexKey, Octant::NavMesh>::Element *F = g.navmesh_ids.front(); F; F = F->next()) {
if (cell_map.has(F->key()) && F->get().id < 0) {
- Ref<NavigationMesh> nm = theme->get_item_navmesh(cell_map[F->key()].item);
+ Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F->key()].item);
if (nm.is_valid()) {
F->get().id = navigation->navmesh_add(nm, F->get().xform, this);
}
@@ -846,8 +855,13 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &GridMap::set_collision_layer_bit);
ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &GridMap::get_collision_layer_bit);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_theme", "theme"), &GridMap::set_theme);
ClassDB::bind_method(D_METHOD("get_theme"), &GridMap::get_theme);
+#endif // DISABLE_DEPRECATED
+
+ ClassDB::bind_method(D_METHOD("set_mesh_library", "mesh_library"), &GridMap::set_mesh_library);
+ ClassDB::bind_method(D_METHOD("get_mesh_library"), &GridMap::get_mesh_library);
ClassDB::bind_method(D_METHOD("set_cell_size", "size"), &GridMap::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &GridMap::get_cell_size);
@@ -865,7 +879,6 @@ void GridMap::_bind_methods() {
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);
@@ -889,7 +902,11 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_theme", "get_theme");
+#ifndef DISABLE_DEPRECATED
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary", PROPERTY_USAGE_NOEDITOR), "set_theme", "get_theme");
+#endif // DISABLE_DEPRECATED
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
ADD_GROUP("Cell", "cell_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size");
@@ -952,7 +969,7 @@ Array GridMap::get_used_cells() const {
Array GridMap::get_meshes() {
- if (theme.is_null())
+ if (mesh_library.is_null())
return Array();
Vector3 ofs = _get_offset();
@@ -961,9 +978,9 @@ Array GridMap::get_meshes() {
for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
int id = E->get().item;
- if (!theme->has_item(id))
+ if (!mesh_library->has_item(id))
continue;
- Ref<Mesh> mesh = theme->get_item_mesh(id);
+ Ref<Mesh> mesh = mesh_library->get_item_mesh(id);
if (mesh.is_null())
continue;
@@ -1004,7 +1021,7 @@ void GridMap::clear_baked_meshes() {
void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texel_size) {
- if (!theme.is_valid())
+ if (!mesh_library.is_valid())
return;
//generate
@@ -1015,10 +1032,10 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
IndexKey key = E->key();
int item = E->get().item;
- if (!theme->has_item(item))
+ if (!mesh_library->has_item(item))
continue;
- Ref<Mesh> mesh = theme->get_item_mesh(item);
+ Ref<Mesh> mesh = mesh_library->get_item_mesh(item);
if (!mesh.is_valid())
continue;
@@ -1064,7 +1081,6 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool> > >::Element *E = surface_map.front(); E; E = E->next()) {
- print_line("generating mesh " + itos(ofs++) + "/" + itos(surface_map.size()));
Ref<ArrayMesh> mesh;
mesh.instance();
for (Map<Ref<Material>, Ref<SurfaceTool> >::Element *F = E->get().front(); F; F = F->next()) {
@@ -1137,8 +1153,8 @@ GridMap::GridMap() {
GridMap::~GridMap() {
- if (!theme.is_null())
- theme->unregister_owner(this);
+ if (!mesh_library.is_null())
+ mesh_library->unregister_owner(this);
clear();
}
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index ed36751fc8..3d8be5c9c7 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -157,7 +157,7 @@ class GridMap : public Spatial {
Vector3::Axis clip_axis;
- Ref<MeshLibrary> theme;
+ Ref<MeshLibrary> mesh_library;
Map<OctantKey, Octant *> octant_map;
Map<IndexKey, Cell> cell_map;
@@ -227,8 +227,13 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
+#ifndef DISABLE_DEPRECATED
void set_theme(const Ref<MeshLibrary> &p_theme);
Ref<MeshLibrary> get_theme() const;
+#endif // DISABLE_DEPRECATED
+
+ void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
+ Ref<MeshLibrary> get_mesh_library() const;
void set_cell_size(const Vector3 &p_size);
Vector3 get_cell_size() const;
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index fc5972c810..90e28129cc 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -43,7 +43,7 @@ void GridMapEditor::_node_removed(Node *p_node) {
if (p_node == node) {
node = NULL;
hide();
- theme_pallete->hide();
+ mesh_library_palette->hide();
}
}
@@ -320,12 +320,12 @@ bool GridMapEditor::do_input_action(Camera *p_camera, const Point2 &p_point, boo
if (!spatial_editor)
return false;
- if (selected_pallete < 0 && input_action != INPUT_COPY && input_action != INPUT_SELECT && input_action != INPUT_DUPLICATE)
+ if (selected_palette < 0 && input_action != INPUT_COPY && input_action != INPUT_SELECT && input_action != INPUT_DUPLICATE)
return false;
- Ref<MeshLibrary> theme = node->get_theme();
- if (theme.is_null())
+ Ref<MeshLibrary> mesh_library = node->get_mesh_library();
+ if (mesh_library.is_null())
return false;
- if (input_action != INPUT_COPY && input_action != INPUT_SELECT && input_action != INPUT_DUPLICATE && !theme->has_item(selected_pallete))
+ if (input_action != INPUT_COPY && input_action != INPUT_SELECT && input_action != INPUT_DUPLICATE && !mesh_library->has_item(selected_palette))
return false;
Camera *camera = p_camera;
@@ -407,9 +407,9 @@ bool GridMapEditor::do_input_action(Camera *p_camera, const Point2 &p_point, boo
int item = node->get_cell_item(cell[0], cell[1], cell[2]);
if (item >= 0) {
- selected_pallete = item;
- theme_pallete->set_current(item);
- update_pallete();
+ selected_palette = item;
+ mesh_library_palette->set_current(item);
+ update_palette();
_update_cursor_instance();
}
return true;
@@ -417,12 +417,12 @@ bool GridMapEditor::do_input_action(Camera *p_camera, const Point2 &p_point, boo
if (input_action == INPUT_PAINT) {
SetItem si;
si.pos = Vector3(cell[0], cell[1], cell[2]);
- si.new_value = selected_pallete;
+ si.new_value = selected_palette;
si.new_orientation = cursor_rot;
si.old_value = node->get_cell_item(cell[0], cell[1], cell[2]);
si.old_orientation = node->get_cell_item_orientation(cell[0], cell[1], cell[2]);
set_items.push_back(si);
- node->set_cell_item(cell[0], cell[1], cell[2], selected_pallete, cursor_rot);
+ node->set_cell_item(cell[0], cell[1], cell[2], selected_palette, cursor_rot);
return true;
} else if (input_action == INPUT_ERASE) {
SetItem si;
@@ -474,7 +474,7 @@ void GridMapEditor::_fill_selection() {
for (int k = selection.begin.z; k <= selection.end.z; k++) {
- undo_redo->add_do_method(node, "set_cell_item", i, j, k, selected_pallete, cursor_rot);
+ undo_redo->add_do_method(node, "set_cell_item", i, j, k, selected_palette, cursor_rot);
undo_redo->add_undo_method(node, "set_cell_item", i, j, k, node->get_cell_item(i, j, k), node->get_cell_item_orientation(i, j, k));
}
}
@@ -712,42 +712,42 @@ void GridMapEditor::_set_display_mode(int p_mode) {
display_mode = p_mode;
- update_pallete();
+ update_palette();
}
-void GridMapEditor::update_pallete() {
- int selected = theme_pallete->get_current();
+void GridMapEditor::update_palette() {
+ int selected = mesh_library_palette->get_current();
- theme_pallete->clear();
+ mesh_library_palette->clear();
if (display_mode == DISPLAY_THUMBNAIL) {
- theme_pallete->set_max_columns(0);
- theme_pallete->set_icon_mode(ItemList::ICON_MODE_TOP);
+ mesh_library_palette->set_max_columns(0);
+ mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_TOP);
} else if (display_mode == DISPLAY_LIST) {
- theme_pallete->set_max_columns(1);
- theme_pallete->set_icon_mode(ItemList::ICON_MODE_LEFT);
+ mesh_library_palette->set_max_columns(1);
+ mesh_library_palette->set_icon_mode(ItemList::ICON_MODE_LEFT);
}
float min_size = EDITOR_DEF("editors/grid_map/preview_size", 64);
- theme_pallete->set_fixed_icon_size(Size2(min_size, min_size));
- theme_pallete->set_fixed_column_width(min_size * 3 / 2);
- theme_pallete->set_max_text_lines(2);
+ mesh_library_palette->set_fixed_icon_size(Size2(min_size, min_size));
+ mesh_library_palette->set_fixed_column_width(min_size * 3 / 2);
+ mesh_library_palette->set_max_text_lines(2);
- Ref<MeshLibrary> theme = node->get_theme();
+ Ref<MeshLibrary> mesh_library = node->get_mesh_library();
- if (theme.is_null()) {
- last_theme = NULL;
+ if (mesh_library.is_null()) {
+ last_mesh_library = NULL;
return;
}
Vector<int> ids;
- ids = theme->get_item_list();
+ ids = mesh_library->get_item_list();
List<_CGMEItemSort> il;
for (int i = 0; i < ids.size(); i++) {
_CGMEItemSort is;
is.id = ids[i];
- is.name = theme->get_item_name(ids[i]);
+ is.name = mesh_library->get_item_name(ids[i]);
il.push_back(is);
}
il.sort();
@@ -757,28 +757,28 @@ void GridMapEditor::update_pallete() {
for (List<_CGMEItemSort>::Element *E = il.front(); E; E = E->next()) {
int id = E->get().id;
- theme_pallete->add_item("");
+ mesh_library_palette->add_item("");
- String name = theme->get_item_name(id);
- Ref<Texture> preview = theme->get_item_preview(id);
+ String name = mesh_library->get_item_name(id);
+ Ref<Texture> preview = mesh_library->get_item_preview(id);
if (!preview.is_null()) {
- theme_pallete->set_item_icon(item, preview);
- theme_pallete->set_item_tooltip(item, name);
+ mesh_library_palette->set_item_icon(item, preview);
+ mesh_library_palette->set_item_tooltip(item, name);
}
if (name != "") {
- theme_pallete->set_item_text(item, name);
+ mesh_library_palette->set_item_text(item, name);
}
- theme_pallete->set_item_metadata(item, id);
+ mesh_library_palette->set_item_metadata(item, id);
item++;
}
if (selected != -1) {
- theme_pallete->select(selected);
+ mesh_library_palette->select(selected);
}
- last_theme = theme.operator->();
+ last_mesh_library = mesh_library.operator->();
}
void GridMapEditor::edit(GridMap *p_gridmap) {
@@ -805,7 +805,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
return;
}
- update_pallete();
+ update_palette();
set_process(true);
@@ -914,7 +914,7 @@ void GridMapEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- theme_pallete->connect("item_selected", this, "_item_selected_cbk");
+ mesh_library_palette->connect("item_selected", this, "_item_selected_cbk");
for (int i = 0; i < 3; i++) {
grid[i] = VS::get_singleton()->mesh_create();
@@ -959,9 +959,9 @@ void GridMapEditor::_notification(int p_what) {
}
grid_xform = xf;
}
- Ref<MeshLibrary> cgmt = node->get_theme();
- if (cgmt.operator->() != last_theme)
- update_pallete();
+ Ref<MeshLibrary> cgmt = node->get_mesh_library();
+ if (cgmt.operator->() != last_mesh_library)
+ update_palette();
if (lock_view) {
@@ -994,10 +994,10 @@ void GridMapEditor::_update_cursor_instance() {
VisualServer::get_singleton()->free(cursor_instance);
cursor_instance = RID();
- if (selected_pallete >= 0) {
+ if (selected_palette >= 0) {
- if (node && !node->get_theme().is_null()) {
- Ref<Mesh> mesh = node->get_theme()->get_item_mesh(selected_pallete);
+ if (node && !node->get_mesh_library().is_null()) {
+ Ref<Mesh> mesh = node->get_mesh_library()->get_item_mesh(selected_palette);
if (!mesh.is_null() && mesh->get_rid().is_valid()) {
cursor_instance = VisualServer::get_singleton()->instance_create2(mesh->get_rid(), get_tree()->get_root()->get_world()->get_scenario());
@@ -1008,7 +1008,7 @@ void GridMapEditor::_update_cursor_instance() {
}
void GridMapEditor::_item_selected_cbk(int idx) {
- selected_pallete = theme_pallete->get_item_metadata(idx);
+ selected_palette = mesh_library_palette->get_item_metadata(idx);
_update_cursor_instance();
}
@@ -1146,9 +1146,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
display_mode = DISPLAY_THUMBNAIL;
- theme_pallete = memnew(ItemList);
- add_child(theme_pallete);
- theme_pallete->set_v_size_flags(SIZE_EXPAND_FILL);
+ mesh_library_palette = memnew(ItemList);
+ add_child(mesh_library_palette);
+ mesh_library_palette->set_v_size_flags(SIZE_EXPAND_FILL);
edit_axis = Vector3::AXIS_Y;
edit_floor[0] = -1;
@@ -1156,7 +1156,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
edit_floor[2] = -1;
cursor_visible = false;
- selected_pallete = -1;
+ selected_palette = -1;
lock_view = false;
cursor_rot = 0;
last_mouseover = Vector3(-1, -1, -1);
@@ -1315,9 +1315,24 @@ GridMapEditor::~GridMapEditor() {
VisualServer::get_singleton()->free(duplicate_instance);
}
+void GridMapEditorPlugin::_notification(int p_what) {
+
+ if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
+
+ switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) {
+ case 0: { // Left.
+ SpatialEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 0);
+ } break;
+ case 1: { // Right.
+ SpatialEditor::get_singleton()->get_palette_split()->move_child(grid_map_editor, 1);
+ } break;
+ }
+ }
+}
+
void GridMapEditorPlugin::edit(Object *p_object) {
- gridmap_editor->edit(Object::cast_to<GridMap>(p_object));
+ grid_map_editor->edit(Object::cast_to<GridMap>(p_object));
}
bool GridMapEditorPlugin::handles(Object *p_object) const {
@@ -1328,29 +1343,35 @@ bool GridMapEditorPlugin::handles(Object *p_object) const {
void GridMapEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- gridmap_editor->show();
- gridmap_editor->spatial_editor_hb->show();
- gridmap_editor->set_process(true);
+ grid_map_editor->show();
+ grid_map_editor->spatial_editor_hb->show();
+ grid_map_editor->set_process(true);
} else {
- gridmap_editor->spatial_editor_hb->hide();
- gridmap_editor->hide();
- gridmap_editor->edit(NULL);
- gridmap_editor->set_process(false);
+ grid_map_editor->spatial_editor_hb->hide();
+ grid_map_editor->hide();
+ grid_map_editor->edit(NULL);
+ grid_map_editor->set_process(false);
}
}
GridMapEditorPlugin::GridMapEditorPlugin(EditorNode *p_node) {
editor = p_node;
- gridmap_editor = memnew(GridMapEditor(editor));
- SpatialEditor::get_singleton()->get_palette_split()->add_child(gridmap_editor);
- // TODO: make this configurable, so the user can choose were to put this, it makes more sense
- // on the right, but some people might find it strange.
- SpatialEditor::get_singleton()->get_palette_split()->move_child(gridmap_editor, 1);
+ EDITOR_DEF("editors/grid_map/editor_side", 1);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/grid_map/editor_side", PROPERTY_HINT_ENUM, "Left,Right"));
- gridmap_editor->hide();
+ grid_map_editor = memnew(GridMapEditor(editor));
+ switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) {
+ case 0: { // Left.
+ add_control_to_container(CONTAINER_SPATIAL_EDITOR_SIDE_LEFT, grid_map_editor);
+ } break;
+ case 1: { // Right.
+ add_control_to_container(CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT, grid_map_editor);
+ } break;
+ }
+ grid_map_editor->hide();
}
GridMapEditorPlugin::~GridMapEditorPlugin() {
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 7c5feda125..663274f46e 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -97,7 +97,7 @@ class GridMapEditor : public VBoxContainer {
List<SetItem> set_items;
GridMap *node;
- MeshLibrary *last_theme;
+ MeshLibrary *last_mesh_library;
ClipMode clip_mode;
bool lock_view;
@@ -141,7 +141,7 @@ class GridMapEditor : public VBoxContainer {
Vector3 last_mouseover;
int display_mode;
- int selected_pallete;
+ int selected_palette;
int cursor_rot;
enum Menu {
@@ -185,9 +185,9 @@ class GridMapEditor : public VBoxContainer {
void update_grid();
void _configure();
void _menu_option(int);
- void update_pallete();
+ void update_palette();
void _set_display_mode(int p_mode);
- ItemList *theme_pallete;
+ ItemList *mesh_library_palette;
void _item_selected_cbk(int idx);
void _update_cursor_transform();
void _update_cursor_instance();
@@ -207,7 +207,6 @@ class GridMapEditor : public VBoxContainer {
bool do_input_action(Camera *p_camera, const Point2 &p_point, bool p_click);
friend class GridMapEditorPlugin;
- Panel *theme_panel;
protected:
void _notification(int p_what);
@@ -227,11 +226,14 @@ class GridMapEditorPlugin : public EditorPlugin {
GDCLASS(GridMapEditorPlugin, EditorPlugin);
- GridMapEditor *gridmap_editor;
+ GridMapEditor *grid_map_editor;
EditorNode *editor;
+protected:
+ void _notification(int p_what);
+
public:
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return gridmap_editor->forward_spatial_input_event(p_camera, p_event); }
+ virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
virtual String get_name() const { return "GridMap"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 2ec00aa72d..e2c630565f 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -297,6 +297,47 @@ bool MobileVRInterface::initialize() {
mag_current_min = Vector3(0, 0, 0);
mag_current_max = Vector3(0, 0, 0);
+ // build our shader
+ if (lens_shader == NULL) {
+ ///@TODO need to switch between GLES2 and GLES3 version, Reduz suggested moving this into our drivers and making this a core shader
+ // create a shader
+ lens_shader = new LensDistortedShaderGLES3();
+
+ // create our shader stuff
+ lens_shader->init();
+
+ glGenBuffers(1, &half_screen_quad);
+ glBindBuffer(GL_ARRAY_BUFFER, half_screen_quad);
+ {
+ /* clang-format off */
+ const float qv[16] = {
+ 0, -1,
+ -1, -1,
+ 0, 1,
+ -1, 1,
+ 1, 1,
+ 1, 1,
+ 1, -1,
+ 1, -1,
+ };
+ /* clang-format on */
+
+ 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
+ }
+
// reset our orientation
orientation = Basis();
@@ -304,7 +345,7 @@ bool MobileVRInterface::initialize() {
arvr_server->set_primary_interface(this);
last_ticks = OS::get_singleton()->get_ticks_usec();
- ;
+
initialized = true;
};
@@ -319,6 +360,15 @@ void MobileVRInterface::uninitialize() {
arvr_server->clear_primary_interface_if(this);
}
+ // cleanup our shader and buffers
+ if (lens_shader != NULL) {
+ glDeleteVertexArrays(1, &half_screen_array);
+ glDeleteBuffers(1, &half_screen_quad);
+
+ delete lens_shader;
+ lens_shader = NULL;
+ }
+
initialized = false;
};
};
@@ -394,6 +444,9 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t
// We must have a valid render target
ERR_FAIL_COND(!p_render_target.is_valid());
+ // We must have an initialised shader
+ ERR_FAIL_COND(lens_shader != NULL);
+
// Because we are rendering to our device we must use our main viewport!
ERR_FAIL_COND(p_screen_rect == Rect2());
@@ -420,13 +473,13 @@ void MobileVRInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_t
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);
+ 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);
@@ -454,41 +507,7 @@ MobileVRInterface::MobileVRInterface() {
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);
- {
- /* clang-format off */
- const float qv[16] = {
- 0, -1,
- -1, -1,
- 0, 1,
- -1, 1,
- 1, 1,
- 1, 1,
- 1, -1,
- 1, -1,
- };
- /* clang-format on */
-
- 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
- }
+ lens_shader = NULL;
};
MobileVRInterface::~MobileVRInterface() {
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index 7b2344f1fe..cee0cca90e 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -58,7 +58,7 @@ private:
float eye_height;
uint64_t last_ticks;
- LensDistortedShaderGLES3 lens_shader;
+ LensDistortedShaderGLES3 *lens_shader;
GLuint half_screen_quad;
GLuint half_screen_array;
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index a2df83925c..f3cf4c9c5d 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -18,14 +18,20 @@ def make_cs_files_header(src, dst):
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:
+ latest_mtime = 0
+ for root, _, files in os.walk(src):
+ files = [f for f in files if f.endswith('.cs')]
+ for file in files:
+ filepath = os.path.join(root, file)
+ filepath_src_rel = os.path.relpath(filepath, src)
+ mtime = os.path.getmtime(filepath)
+ latest_mtime = mtime if mtime > latest_mtime else latest_mtime
+ with open(filepath, 'rb') as f:
buf = f.read()
decomp_size = len(buf)
import zlib
buf = zlib.compress(buf)
- name = os.path.splitext(file)[0]
+ name = os.path.splitext(os.path.normpath(filepath_src_rel))[0].strip(os.sep).replace(os.sep, '_').replace('.', '_dotto_')
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[] = { ')
@@ -33,18 +39,13 @@ def make_cs_files_header(src, dst):
if i > 0:
header.write(', ')
header.write(byte_to_str(buf[buf_idx]))
- inserted_files += '\tr_files.insert("' + file + '", ' \
+ inserted_files += '\tr_files.insert("' + filepath_src_rel + '", ' \
'CompressedFile(_cs_' + name + '_compressed_size, ' \
'_cs_' + name + '_uncompressed_size, ' \
'_cs_' + name + '_compressed));\n'
header.write(' };\n')
- version_file = os.path.join(src, 'VERSION.txt')
- with open(version_file, 'r') as content_file:
- try:
- glue_version = int(content_file.read()) # make sure the format is valid
- header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\n')
- except ValueError:
- raise ValueError('Invalid C# glue version in: ' + version_file)
+ glue_version = int(latest_mtime) # The latest modified time will do for now
+ header.write('\n#define CS_GLUE_VERSION UINT32_C(' + str(glue_version) + ')\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'
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 9a000a2a72..70fd1a35f1 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -83,6 +83,8 @@ def configure(env):
mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
if env['platform'] == 'windows':
+ mono_root = ''
+
if bits == '32':
if os.getenv('MONO32_PREFIX'):
mono_root = os.getenv('MONO32_PREFIX')
@@ -263,11 +265,13 @@ def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
def pkgconfig_try_find_mono_version():
+ from compat import decode_utf8
+
lines = subprocess.check_output(['pkg-config', 'monosgen-2', '--modversion']).splitlines()
greater_version = None
for line in lines:
try:
- version = LooseVersion(line)
+ version = LooseVersion(decode_utf8(line))
if greater_version is None or version > greater_version:
greater_version = version
except ValueError:
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 7d7028a7a6..b8b77924f7 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -736,6 +736,9 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
obj->get_script_instance()->get_property_state(state);
map[obj->get_instance_id()] = state;
obj->set_script(RefPtr());
+ } else {
+ // no instance found. Let's remove it so we don't loop forever
+ E->get()->placeholders.erase(E->get()->placeholders.front()->get());
}
}
@@ -747,8 +750,24 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
}
}
- if (gdmono->reload_scripts_domain() != OK)
+ if (gdmono->reload_scripts_domain() != OK) {
+ // Failed to reload the scripts domain
+ // Make sure to add the scripts back to their owners before returning
+ for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
+ Ref<CSharpScript> scr = E->key();
+ 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;
+ obj->set_script(scr.get_ref_ptr());
+ // 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();
+ }
+ }
+ }
return;
+ }
for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) {
@@ -778,6 +797,14 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
continue;
}
+ if (scr->valid && scr->is_tool() && obj->get_script_instance()->is_placeholder()) {
+ // Script instance was a placeholder, but now the script was built successfully and is a tool script.
+ // We have to replace the placeholder with an actual C# script instance.
+ scr->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(obj->get_script_instance()));
+ ScriptInstance *script_instance = scr->instance_create(obj);
+ obj->set_script_instance(script_instance); // Not necessary as it's already done in instance_create, but just in case...
+ }
+
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);
}
@@ -1474,8 +1501,12 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List
bool CSharpScript::_update_exports() {
#ifdef TOOLS_ENABLED
- if (!valid)
+ if (!valid) {
+ for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->set_build_failed(true);
+ }
return false;
+ }
bool changed = false;
@@ -1577,6 +1608,7 @@ bool CSharpScript::_update_exports() {
_update_exports_values(values, propnames);
for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ E->get()->set_build_failed(false);
E->get()->update(propnames, values);
}
}
@@ -1687,7 +1719,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p
MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute));
- PropertyHint hint;
+ PropertyHint hint = PROPERTY_HINT_NONE;
String hint_string;
if (variant_type == Variant::NIL) {
@@ -1873,7 +1905,11 @@ bool CSharpScript::can_instance() const {
}
#endif
- return valid || (!tool && !ScriptServer::is_scripting_enabled());
+#ifdef TOOLS_ENABLED
+ return valid && (tool || ScriptServer::is_scripting_enabled());
+#else
+ return valid;
+#endif
}
StringName CSharpScript::get_instance_base_type() const {
@@ -1971,16 +2007,9 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call
ScriptInstance *CSharpScript::instance_create(Object *p_this) {
- 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;
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!valid);
#endif
- }
if (!script_class) {
if (GDMono::get_singleton()->get_project_assembly() == NULL) {
@@ -2011,6 +2040,18 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error);
}
+PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) {
+
+#ifdef TOOLS_ENABLED
+ PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this));
+ placeholders.insert(si);
+ _update_exports();
+ return si;
+#else
+ return NULL;
+#endif
+}
+
bool CSharpScript::instance_has(const Object *p_this) const {
#ifndef NO_THREADS
@@ -2077,9 +2118,7 @@ Error CSharpScript::reload(bool p_keep_state) {
if (script_class) {
#ifdef DEBUG_ENABLED
- OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." +
- script_class->get_name() + " for script " + get_path() + "\n")
- .utf8());
+ print_verbose("Found class " + script_class->get_namespace() + "." + script_class->get_name() + " for script " + get_path());
#endif
tool = script_class->has_attribute(CACHED_CLASS(ToolAttribute));
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 7f9732c297..53644eafae 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -139,6 +139,7 @@ public:
virtual bool can_instance() const;
virtual StringName get_instance_base_type() const;
virtual ScriptInstance *instance_create(Object *p_this);
+ virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this);
virtual bool instance_has(const Object *p_this) const;
virtual bool has_source_code() const;
@@ -292,7 +293,7 @@ public:
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, Set<int> *r_safe_lines = NULL) const { return true; }
+ /* 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, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const { return true; }
virtual String validate_path(const String &p_path) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 76907451e7..b97bb5e95f 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -512,6 +512,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
data.resize(file_data.uncompressed_size);
Compression::decompress(data.ptrw(), file_data.uncompressed_size, file_data.data, file_data.compressed_size, Compression::MODE_DEFLATE);
+ String output_dir = output_file.get_base_dir();
+
+ if (!DirAccess::exists(output_dir)) {
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(output_dir));
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+ }
+
FileAccessRef file = FileAccess::open(output_file, FileAccess::WRITE);
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
file->store_buffer(data.ptr(), data.size());
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index b3b259e851..2faab1718d 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -97,8 +97,7 @@ MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
}
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print("Cannot find executable for '" PROP_NAME_MSBUILD_VS "'. Trying with '" PROP_NAME_MSBUILD_MONO "'...\n");
+ print_verbose("Cannot find executable for '" PROP_NAME_MSBUILD_VS "'. Trying with '" PROP_NAME_MSBUILD_MONO "'...");
} // FALL THROUGH
case GodotSharpBuilds::MSBUILD_MONO: {
String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat");
@@ -210,6 +209,8 @@ bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_s
if (!FileAccess::exists(api_assembly_file)) {
MonoBuildInfo api_build_info(api_sln_file, p_config);
+ // TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
+ // once we start to actively document manually maintained C# classes
api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
@@ -554,8 +555,9 @@ void GodotSharpBuilds::BuildProcess::start(bool 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());
+ if (exit_code != 0) {
+ print_verbose("MSBuild finished with exit code " + itos(exit_code));
+ }
build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
} else {
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 0551c1991a..148bb32398 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -182,7 +182,7 @@ bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
}
bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
- return ptr->erase_checked(GDMonoMarshal::mono_object_to_variant(key));
+ return ptr->erase(GDMonoMarshal::mono_object_to_variant(key));
}
bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
@@ -191,7 +191,7 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject
// no dupes
Variant *ret = ptr->getptr(varKey);
if (ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
- ptr->erase_checked(varKey);
+ ptr->erase(varKey);
return true;
}
diff --git a/modules/mono/glue/cs_files/AABB.cs b/modules/mono/glue/cs_files/AABB.cs
index 39f2d2ed51..0df2e615f1 100644
--- a/modules/mono/glue/cs_files/AABB.cs
+++ b/modules/mono/glue/cs_files/AABB.cs
@@ -15,39 +15,33 @@ namespace Godot
{
public struct AABB : IEquatable<AABB>
{
- private Vector3 position;
- private Vector3 size;
+ private Vector3 _position;
+ private Vector3 _size;
public Vector3 Position
{
- get
- {
- return position;
- }
+ get { return _position; }
+ set { _position = value; }
}
public Vector3 Size
{
- get
- {
- return size;
- }
+ get { return _size; }
+ set { _size = value; }
}
public Vector3 End
{
- get
- {
- return position + size;
- }
+ get { return _position + _size; }
+ set { _size = value - _position; }
}
public bool Encloses(AABB with)
{
- Vector3 src_min = position;
- Vector3 src_max = position + size;
- Vector3 dst_min = with.position;
- Vector3 dst_max = with.position + with.size;
+ 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 &&
@@ -59,8 +53,8 @@ namespace Godot
public AABB Expand(Vector3 to_point)
{
- Vector3 begin = position;
- Vector3 end = position + size;
+ Vector3 begin = _position;
+ Vector3 end = _position + _size;
if (to_point.x < begin.x)
begin.x = to_point.x;
@@ -81,7 +75,7 @@ namespace Godot
public real_t GetArea()
{
- return size.x * size.y * size.z;
+ return _size.x * _size.y * _size.z;
}
public Vector3 GetEndpoint(int idx)
@@ -89,21 +83,21 @@ namespace Godot
switch (idx)
{
case 0:
- return new Vector3(position.x, position.y, position.z);
+ return new Vector3(_position.x, _position.y, _position.z);
case 1:
- return new Vector3(position.x, position.y, position.z + size.z);
+ return new Vector3(_position.x, _position.y, _position.z + _size.z);
case 2:
- return new Vector3(position.x, position.y + size.y, position.z);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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));
}
@@ -112,15 +106,15 @@ namespace Godot
public Vector3 GetLongestAxis()
{
var axis = new Vector3(1f, 0f, 0f);
- real_t max_size = size.x;
+ real_t max_size = _size.x;
- if (size.y > max_size)
+ if (_size.y > max_size)
{
axis = new Vector3(0f, 1f, 0f);
- max_size = size.y;
+ max_size = _size.y;
}
- if (size.z > max_size)
+ if (_size.z > max_size)
{
axis = new Vector3(0f, 0f, 1f);
}
@@ -131,15 +125,15 @@ namespace Godot
public Vector3.Axis GetLongestAxisIndex()
{
var axis = Vector3.Axis.X;
- real_t max_size = size.x;
+ real_t max_size = _size.x;
- if (size.y > max_size)
+ if (_size.y > max_size)
{
axis = Vector3.Axis.Y;
- max_size = size.y;
+ max_size = _size.y;
}
- if (size.z > max_size)
+ if (_size.z > max_size)
{
axis = Vector3.Axis.Z;
}
@@ -149,13 +143,13 @@ namespace Godot
public real_t GetLongestAxisSize()
{
- real_t max_size = size.x;
+ real_t max_size = _size.x;
- if (size.y > max_size)
- max_size = size.y;
+ if (_size.y > max_size)
+ max_size = _size.y;
- if (size.z > max_size)
- max_size = size.z;
+ if (_size.z > max_size)
+ max_size = _size.z;
return max_size;
}
@@ -163,15 +157,15 @@ namespace Godot
public Vector3 GetShortestAxis()
{
var axis = new Vector3(1f, 0f, 0f);
- real_t max_size = size.x;
+ real_t max_size = _size.x;
- if (size.y < max_size)
+ if (_size.y < max_size)
{
axis = new Vector3(0f, 1f, 0f);
- max_size = size.y;
+ max_size = _size.y;
}
- if (size.z < max_size)
+ if (_size.z < max_size)
{
axis = new Vector3(0f, 0f, 1f);
}
@@ -182,15 +176,15 @@ namespace Godot
public Vector3.Axis GetShortestAxisIndex()
{
var axis = Vector3.Axis.X;
- real_t max_size = size.x;
+ real_t max_size = _size.x;
- if (size.y < max_size)
+ if (_size.y < max_size)
{
axis = Vector3.Axis.Y;
- max_size = size.y;
+ max_size = _size.y;
}
- if (size.z < max_size)
+ if (_size.z < max_size)
{
axis = Vector3.Axis.Z;
}
@@ -200,21 +194,21 @@ namespace Godot
public real_t GetShortestAxisSize()
{
- real_t max_size = size.x;
+ real_t max_size = _size.x;
- if (size.y < max_size)
- max_size = size.y;
+ if (_size.y < max_size)
+ max_size = _size.y;
- if (size.z < max_size)
- max_size = size.z;
+ if (_size.z < max_size)
+ max_size = _size.z;
return max_size;
}
public Vector3 GetSupport(Vector3 dir)
{
- Vector3 half_extents = size * 0.5f;
- Vector3 ofs = position + half_extents;
+ Vector3 half_extents = _size * 0.5f;
+ Vector3 ofs = _position + half_extents;
return ofs + new Vector3(
dir.x > 0f ? -half_extents.x : half_extents.x,
@@ -226,39 +220,39 @@ namespace Godot
{
var 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;
+ 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 HasNoArea()
{
- return size.x <= 0f || size.y <= 0f || size.z <= 0f;
+ return _size.x <= 0f || _size.y <= 0f || _size.z <= 0f;
}
public bool HasNoSurface()
{
- return size.x <= 0f && size.y <= 0f && size.z <= 0f;
+ return _size.x <= 0f && _size.y <= 0f && _size.z <= 0f;
}
public bool HasPoint(Vector3 point)
{
- if (point.x < position.x)
+ if (point.x < _position.x)
return false;
- if (point.y < position.y)
+ if (point.y < _position.y)
return false;
- if (point.z < position.z)
+ if (point.z < _position.z)
return false;
- if (point.x > position.x + size.x)
+ if (point.x > _position.x + _size.x)
return false;
- if (point.y > position.y + size.y)
+ if (point.y > _position.y + _size.y)
return false;
- if (point.z > position.z + size.z)
+ if (point.z > _position.z + _size.z)
return false;
return true;
@@ -266,10 +260,10 @@ namespace Godot
public AABB Intersection(AABB with)
{
- Vector3 src_min = position;
- Vector3 src_max = position + size;
- Vector3 dst_min = with.position;
- Vector3 dst_max = with.position + with.size;
+ Vector3 src_min = _position;
+ Vector3 src_max = _position + _size;
+ Vector3 dst_min = with._position;
+ Vector3 dst_max = with._position + with._size;
Vector3 min, max;
@@ -302,17 +296,17 @@ namespace Godot
public bool Intersects(AABB with)
{
- if (position.x >= with.position.x + with.size.x)
+ if (_position.x >= with._position.x + with._size.x)
return false;
- if (position.x + size.x <= with.position.x)
+ if (_position.x + _size.x <= with._position.x)
return false;
- if (position.y >= with.position.y + with.size.y)
+ if (_position.y >= with._position.y + with._size.y)
return false;
- if (position.y + size.y <= with.position.y)
+ if (_position.y + _size.y <= with._position.y)
return false;
- if (position.z >= with.position.z + with.size.z)
+ if (_position.z >= with._position.z + with._size.z)
return false;
- if (position.z + size.z <= with.position.z)
+ if (_position.z + _size.z <= with._position.z)
return false;
return true;
@@ -322,14 +316,14 @@ namespace Godot
{
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)
+ 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;
@@ -355,8 +349,8 @@ namespace Godot
{
real_t seg_from = from[i];
real_t seg_to = to[i];
- real_t box_begin = position[i];
- real_t box_end = box_begin + size[i];
+ real_t box_begin = _position[i];
+ real_t box_end = box_begin + _size[i];
real_t cmin, cmax;
if (seg_from < seg_to)
@@ -394,10 +388,10 @@ namespace Godot
public AABB Merge(AABB with)
{
- Vector3 beg_1 = position;
- Vector3 beg_2 = with.position;
- var end_1 = new Vector3(size.x, size.y, size.z) + beg_1;
- var end_2 = new Vector3(with.size.x, with.size.y, with.size.z) + beg_2;
+ Vector3 beg_1 = _position;
+ Vector3 beg_2 = with._position;
+ var end_1 = new Vector3(_size.x, _size.y, _size.z) + beg_1;
+ var end_2 = new Vector3(with._size.x, with._size.y, with._size.z) + beg_2;
var min = new Vector3(
beg_1.x < beg_2.x ? beg_1.x : beg_2.x,
@@ -417,8 +411,8 @@ namespace Godot
// Constructors
public AABB(Vector3 position, Vector3 size)
{
- this.position = position;
- this.size = size;
+ _position = position;
+ _size = size;
}
public static bool operator ==(AABB left, AABB right)
@@ -443,20 +437,20 @@ namespace Godot
public bool Equals(AABB other)
{
- return position == other.position && size == other.size;
+ return _position == other._position && _size == other._size;
}
public override int GetHashCode()
{
- return position.GetHashCode() ^ size.GetHashCode();
+ return _position.GetHashCode() ^ _size.GetHashCode();
}
public override string ToString()
{
return String.Format("{0} - {1}", new object[]
{
- position.ToString(),
- size.ToString()
+ _position.ToString(),
+ _size.ToString()
});
}
@@ -464,8 +458,8 @@ namespace Godot
{
return String.Format("{0} - {1}", new object[]
{
- position.ToString(format),
- size.ToString(format)
+ _position.ToString(format),
+ _size.ToString(format)
});
}
}
diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/cs_files/Array.cs
index 51f57daef4..1ec4d7d20a 100644
--- a/modules/mono/glue/cs_files/Array.cs
+++ b/modules/mono/glue/cs_files/Array.cs
@@ -331,5 +331,10 @@ namespace Godot
{
return GetEnumerator();
}
+
+ internal IntPtr GetPtr()
+ {
+ return objectArray.GetPtr();
+ }
}
}
diff --git a/modules/mono/glue/cs_files/Attributes/ExportAttribute.cs b/modules/mono/glue/cs_files/Attributes/ExportAttribute.cs
new file mode 100644
index 0000000000..6adf044886
--- /dev/null
+++ b/modules/mono/glue/cs_files/Attributes/ExportAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public class ExportAttribute : Attribute
+ {
+ private PropertyHint hint;
+ private string hintString;
+
+ public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
+ {
+ this.hint = hint;
+ this.hintString = hintString;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GodotMethodAttribute.cs b/modules/mono/glue/cs_files/Attributes/GodotMethodAttribute.cs
index 55848769d5..55848769d5 100644
--- a/modules/mono/glue/cs_files/GodotMethodAttribute.cs
+++ b/modules/mono/glue/cs_files/Attributes/GodotMethodAttribute.cs
diff --git a/modules/mono/glue/cs_files/RPCAttributes.cs b/modules/mono/glue/cs_files/Attributes/RPCAttributes.cs
index 6bf9560bfa..6bf9560bfa 100644
--- a/modules/mono/glue/cs_files/RPCAttributes.cs
+++ b/modules/mono/glue/cs_files/Attributes/RPCAttributes.cs
diff --git a/modules/mono/glue/cs_files/SignalAttribute.cs b/modules/mono/glue/cs_files/Attributes/SignalAttribute.cs
index 3957387be9..3957387be9 100644
--- a/modules/mono/glue/cs_files/SignalAttribute.cs
+++ b/modules/mono/glue/cs_files/Attributes/SignalAttribute.cs
diff --git a/modules/mono/glue/cs_files/Attributes/ToolAttribute.cs b/modules/mono/glue/cs_files/Attributes/ToolAttribute.cs
new file mode 100644
index 0000000000..d0437409af
--- /dev/null
+++ b/modules/mono/glue/cs_files/Attributes/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/Color.cs b/modules/mono/glue/cs_files/Color.cs
index 1195071bd3..49e04b333a 100644
--- a/modules/mono/glue/cs_files/Color.cs
+++ b/modules/mono/glue/cs_files/Color.cs
@@ -258,11 +258,6 @@ namespace Godot
return res;
}
- public float Gray()
- {
- return (r + g + b) / 3.0f;
- }
-
public Color Inverted()
{
return new Color(
diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/cs_files/Dictionary.cs
index 57a1960ad9..30d17c2a59 100644
--- a/modules/mono/glue/cs_files/Dictionary.cs
+++ b/modules/mono/glue/cs_files/Dictionary.cs
@@ -397,5 +397,10 @@ namespace Godot
{
return GetEnumerator();
}
+
+ internal IntPtr GetPtr()
+ {
+ return objectDict.GetPtr();
+ }
}
}
diff --git a/modules/mono/glue/cs_files/ExportAttribute.cs b/modules/mono/glue/cs_files/ExportAttribute.cs
deleted file mode 100644
index e6f569e1bb..0000000000
--- a/modules/mono/glue/cs_files/ExportAttribute.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-
-namespace Godot
-{
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
- public class ExportAttribute : Attribute
- {
- private PropertyHint hint;
- private string hintString;
-
- public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
- {
- this.hint = hint;
- this.hintString = hintString;
- }
- }
-}
diff --git a/modules/mono/glue/cs_files/NodeExtensions.cs b/modules/mono/glue/cs_files/Extensions/NodeExtensions.cs
index 71534d7782..71534d7782 100644
--- a/modules/mono/glue/cs_files/NodeExtensions.cs
+++ b/modules/mono/glue/cs_files/Extensions/NodeExtensions.cs
diff --git a/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs b/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs
new file mode 100644
index 0000000000..5c9e6609f4
--- /dev/null
+++ b/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Godot
+{
+ public partial class Object
+ {
+ public static bool IsInstanceValid(Object instance)
+ {
+ return instance != null && instance.NativeInstance != IntPtr.Zero;
+ }
+
+ public static WeakRef WeakRef(Object obj)
+ {
+ return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj));
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/cs_files/Extensions/ResourceLoaderExtensions.cs
new file mode 100644
index 0000000000..ceecc589e6
--- /dev/null
+++ b/modules/mono/glue/cs_files/Extensions/ResourceLoaderExtensions.cs
@@ -0,0 +1,10 @@
+namespace Godot
+{
+ public static partial class ResourceLoader
+ {
+ public static T Load<T>(string path) where T : Godot.Resource
+ {
+ return (T) Load(path);
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs
index e2457ff98b..0a5d703f27 100644
--- a/modules/mono/glue/cs_files/GD.cs
+++ b/modules/mono/glue/cs_files/GD.cs
@@ -64,6 +64,11 @@ namespace Godot
return ResourceLoader.Load(path);
}
+ public static T Load<T>(string path) where T : Godot.Resource
+ {
+ return (T) ResourceLoader.Load(path);
+ }
+
public static void Print(params object[] what)
{
NativeCalls.godot_icall_Godot_print(what);
@@ -187,10 +192,5 @@ namespace Godot
{
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/IAwaiter.cs b/modules/mono/glue/cs_files/IAwaiter.cs
deleted file mode 100644
index b5aa1a5389..0000000000
--- a/modules/mono/glue/cs_files/IAwaiter.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-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/IAwaitable.cs b/modules/mono/glue/cs_files/Interfaces/IAwaitable.cs
index 0397957d00..0397957d00 100644
--- a/modules/mono/glue/cs_files/IAwaitable.cs
+++ b/modules/mono/glue/cs_files/Interfaces/IAwaitable.cs
diff --git a/modules/mono/glue/cs_files/Interfaces/IAwaiter.cs b/modules/mono/glue/cs_files/Interfaces/IAwaiter.cs
new file mode 100644
index 0000000000..d3be9d781c
--- /dev/null
+++ b/modules/mono/glue/cs_files/Interfaces/IAwaiter.cs
@@ -0,0 +1,18 @@
+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/Plane.cs b/modules/mono/glue/cs_files/Plane.cs
index 1020f06bf5..9611dce11e 100644
--- a/modules/mono/glue/cs_files/Plane.cs
+++ b/modules/mono/glue/cs_files/Plane.cs
@@ -145,6 +145,15 @@ namespace Godot
return point - _normal * DistanceTo(point);
}
+ // Constants
+ private static readonly Plane _planeYZ = new Plane(1, 0, 0, 0);
+ private static readonly Plane _planeXZ = new Plane(0, 1, 0, 0);
+ private static readonly Plane _planeXY = new Plane(0, 0, 1, 0);
+
+ public static Plane PlaneYZ { get { return _planeYZ; } }
+ public static Plane PlaneXZ { get { return _planeXZ; } }
+ public static Plane PlaneXY { get { return _planeXY; } }
+
// Constructors
public Plane(real_t a, real_t b, real_t c, real_t d)
{
diff --git a/modules/mono/glue/cs_files/Rect2.cs b/modules/mono/glue/cs_files/Rect2.cs
index 6f16656573..cb25c267bc 100644
--- a/modules/mono/glue/cs_files/Rect2.cs
+++ b/modules/mono/glue/cs_files/Rect2.cs
@@ -11,24 +11,25 @@ namespace Godot
[StructLayout(LayoutKind.Sequential)]
public struct Rect2 : IEquatable<Rect2>
{
- private Vector2 position;
- private Vector2 size;
+ private Vector2 _position;
+ private Vector2 _size;
public Vector2 Position
{
- get { return position; }
- set { position = value; }
+ get { return _position; }
+ set { _position = value; }
}
public Vector2 Size
{
- get { return size; }
- set { size = value; }
+ get { return _size; }
+ set { _size = value; }
}
public Vector2 End
{
- get { return position + size; }
+ get { return _position + _size; }
+ set { _size = value - _position; }
}
public real_t Area
@@ -36,6 +37,13 @@ namespace Godot
get { return GetArea(); }
}
+ public Rect2 Abs()
+ {
+ Vector2 end = End;
+ Vector2 topLeft = new Vector2(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y));
+ return new Rect2(topLeft, _size.Abs());
+ }
+
public Rect2 Clip(Rect2 b)
{
var newRect = b;
@@ -43,31 +51,31 @@ namespace Godot
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);
+ 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;
+ 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;
+ 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;
+ 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)
{
var expanded = this;
- Vector2 begin = expanded.position;
- Vector2 end = expanded.position + expanded.size;
+ Vector2 begin = expanded._position;
+ Vector2 end = expanded._position + expanded._size;
if (to.x < begin.x)
begin.x = to.x;
@@ -79,25 +87,25 @@ namespace Godot
if (to.y > end.y)
end.y = to.y;
- expanded.position = begin;
- expanded.size = end - begin;
+ expanded._position = begin;
+ expanded._size = end - begin;
return expanded;
}
public real_t GetArea()
{
- return size.x * size.y;
+ return _size.x * _size.y;
}
public Rect2 Grow(real_t by)
{
var g = this;
- g.position.x -= by;
- g.position.y -= by;
- g.size.x += by * 2;
- g.size.y += by * 2;
+ g._position.x -= by;
+ g._position.y -= by;
+ g._size.x += by * 2;
+ g._size.y += by * 2;
return g;
}
@@ -106,10 +114,10 @@ namespace Godot
{
var g = this;
- g.position.x -= left;
- g.position.y -= top;
- g.size.x += left + right;
- g.size.y += top + bottom;
+ g._position.x -= left;
+ g._position.y -= top;
+ g._size.x += left + right;
+ g._size.y += top + bottom;
return g;
}
@@ -128,19 +136,19 @@ namespace Godot
public bool HasNoArea()
{
- return size.x <= 0 || size.y <= 0;
+ return _size.x <= 0 || _size.y <= 0;
}
public bool HasPoint(Vector2 point)
{
- if (point.x < position.x)
+ if (point.x < _position.x)
return false;
- if (point.y < position.y)
+ if (point.y < _position.y)
return false;
- if (point.x >= position.x + size.x)
+ if (point.x >= _position.x + _size.x)
return false;
- if (point.y >= position.y + size.y)
+ if (point.y >= _position.y + _size.y)
return false;
return true;
@@ -148,13 +156,13 @@ namespace Godot
public bool Intersects(Rect2 b)
{
- if (position.x > b.position.x + b.size.x)
+ if (_position.x > b._position.x + b._size.x)
return false;
- if (position.x + size.x < b.position.x)
+ if (_position.x + _size.x < b._position.x)
return false;
- if (position.y > b.position.y + b.size.y)
+ if (_position.y > b._position.y + b._size.y)
return false;
- if (position.y + size.y < b.position.y)
+ if (_position.y + _size.y < b._position.y)
return false;
return true;
@@ -164,13 +172,13 @@ namespace Godot
{
Rect2 newRect;
- newRect.position.x = Mathf.Min(b.position.x, position.x);
- newRect.position.y = Mathf.Min(b.position.y, position.y);
+ 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.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
+ newRect._size = newRect._size - newRect._position; // Make relative again
return newRect;
}
@@ -178,23 +186,23 @@ namespace Godot
// Constructors
public Rect2(Vector2 position, Vector2 size)
{
- this.position = position;
- this.size = size;
+ _position = position;
+ _size = size;
}
public Rect2(Vector2 position, real_t width, real_t height)
{
- this.position = position;
- size = new Vector2(width, height);
+ _position = position;
+ _size = new Vector2(width, height);
}
public Rect2(real_t x, real_t y, Vector2 size)
{
- position = new Vector2(x, y);
- this.size = size;
+ _position = new Vector2(x, y);
+ _size = size;
}
public Rect2(real_t x, real_t y, real_t width, real_t height)
{
- position = new Vector2(x, y);
- size = new Vector2(width, height);
+ _position = new Vector2(x, y);
+ _size = new Vector2(width, height);
}
public static bool operator ==(Rect2 left, Rect2 right)
@@ -219,20 +227,20 @@ namespace Godot
public bool Equals(Rect2 other)
{
- return position.Equals(other.position) && size.Equals(other.size);
+ return _position.Equals(other._position) && _size.Equals(other._size);
}
public override int GetHashCode()
{
- return position.GetHashCode() ^ size.GetHashCode();
+ return _position.GetHashCode() ^ _size.GetHashCode();
}
public override string ToString()
{
return String.Format("({0}, {1})", new object[]
{
- position.ToString(),
- size.ToString()
+ _position.ToString(),
+ _size.ToString()
});
}
@@ -240,8 +248,8 @@ namespace Godot
{
return String.Format("({0}, {1})", new object[]
{
- position.ToString(format),
- size.ToString(format)
+ _position.ToString(format),
+ _size.ToString(format)
});
}
}
diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/cs_files/StringExtensions.cs
index eaeed7b37b..b58f8bc6a8 100644
--- a/modules/mono/glue/cs_files/StringExtensions.cs
+++ b/modules/mono/glue/cs_files/StringExtensions.cs
@@ -1,5 +1,3 @@
-//using System;
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -583,7 +581,7 @@ namespace Godot
// </summary>
public static byte[] Md5Buffer(this string instance)
{
- return NativeCalls.godot_icall_String_md5_buffer(instance);
+ return NativeCalls.godot_icall_String_md5_buffer(instance);
}
// <summary>
@@ -591,7 +589,7 @@ namespace Godot
// </summary>
public static string Md5Text(this string instance)
{
- return NativeCalls.godot_icall_String_md5_text(instance);
+ return NativeCalls.godot_icall_String_md5_text(instance);
}
// <summary>
@@ -750,7 +748,7 @@ namespace Godot
// </summary>
public static int Rfind(this string instance, string what, int from = -1)
{
- return NativeCalls.godot_icall_String_rfind(instance, what, from);
+ return NativeCalls.godot_icall_String_rfind(instance, what, from);
}
// <summary>
@@ -758,7 +756,7 @@ namespace Godot
// </summary>
public static int Rfindn(this string instance, string what, int from = -1)
{
- return NativeCalls.godot_icall_String_rfindn(instance, what, from);
+ return NativeCalls.godot_icall_String_rfindn(instance, what, from);
}
// <summary>
@@ -777,7 +775,7 @@ namespace Godot
public static byte[] Sha256Buffer(this string instance)
{
- return NativeCalls.godot_icall_String_sha256_buffer(instance);
+ return NativeCalls.godot_icall_String_sha256_buffer(instance);
}
// <summary>
@@ -785,7 +783,7 @@ namespace Godot
// </summary>
public static string Sha256Text(this string instance)
{
- return NativeCalls.godot_icall_String_sha256_text(instance);
+ return NativeCalls.godot_icall_String_sha256_text(instance);
}
// <summary>
diff --git a/modules/mono/glue/cs_files/ToolAttribute.cs b/modules/mono/glue/cs_files/ToolAttribute.cs
deleted file mode 100644
index d8601b5b32..0000000000
--- a/modules/mono/glue/cs_files/ToolAttribute.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-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
index d1b247a552..e432d5b52c 100644
--- a/modules/mono/glue/cs_files/Transform.cs
+++ b/modules/mono/glue/cs_files/Transform.cs
@@ -102,7 +102,18 @@ namespace Godot
basis[0, 2] * vInv.x + basis[1, 2] * vInv.y + basis[2, 2] * vInv.z
);
}
-
+
+ // Constants
+ private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero);
+ private static readonly Transform _flipX = new Transform(new Basis(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1)), Vector3.Zero);
+ private static readonly Transform _flipY = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, -1, 0), new Vector3(0, 0, 1)), Vector3.Zero);
+ private static readonly Transform _flipZ = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, -1)), Vector3.Zero);
+
+ public static Transform Identity { get { return _identity; } }
+ public static Transform FlipX { get { return _flipX; } }
+ public static Transform FlipY { get { return _flipY; } }
+ public static Transform FlipZ { get { return _flipZ; } }
+
// Constructors
public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin)
{
diff --git a/modules/mono/glue/cs_files/Transform2D.cs b/modules/mono/glue/cs_files/Transform2D.cs
index ff5259178b..8d30833066 100644
--- a/modules/mono/glue/cs_files/Transform2D.cs
+++ b/modules/mono/glue/cs_files/Transform2D.cs
@@ -11,22 +11,10 @@ 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; }
@@ -264,6 +252,15 @@ namespace Godot
Vector2 vInv = v - o;
return new Vector2(x.Dot(vInv), y.Dot(vInv));
}
+
+ // Constants
+ private static readonly Transform2D _identity = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
+ private static readonly Transform2D _flipX = new Transform2D(new Vector2(-1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
+ private static readonly Transform2D _flipY = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, -1f), Vector2.Zero);
+
+ public static Transform2D Identity { get { return _identity; } }
+ public static Transform2D FlipX { get { return _flipX; } }
+ public static Transform2D FlipY { get { return _flipY; } }
// Constructors
public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin)
diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt
deleted file mode 100755
index 7f8f011eb7..0000000000
--- a/modules/mono/glue/cs_files/VERSION.txt
+++ /dev/null
@@ -1 +0,0 @@
-7
diff --git a/modules/mono/glue/cs_files/Vector2.cs b/modules/mono/glue/cs_files/Vector2.cs
index c274364895..080b8802ba 100644
--- a/modules/mono/glue/cs_files/Vector2.cs
+++ b/modules/mono/glue/cs_files/Vector2.cs
@@ -184,6 +184,11 @@ namespace Godot
return result;
}
+ public Vector2 Project(Vector2 onNormal)
+ {
+ return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
+ }
+
public Vector2 Reflect(Vector2 n)
{
return 2.0f * n * Dot(n) - this;
@@ -231,24 +236,27 @@ namespace Godot
{
return new Vector2(y, -x);
}
-
- private static readonly Vector2 zero = new Vector2 (0, 0);
- private static readonly Vector2 one = new Vector2 (1, 1);
- private static readonly Vector2 negOne = new Vector2 (-1, -1);
-
- private static readonly Vector2 up = new Vector2 (0, 1);
- private static readonly Vector2 down = new Vector2 (0, -1);
- private static readonly Vector2 right = new Vector2 (1, 0);
- private static readonly Vector2 left = new Vector2 (-1, 0);
-
- public static Vector2 Zero { get { return zero; } }
- public static Vector2 One { get { return one; } }
- public static Vector2 NegOne { get { return negOne; } }
-
- public static Vector2 Up { get { return up; } }
- public static Vector2 Down { get { return down; } }
- public static Vector2 Right { get { return right; } }
- public static Vector2 Left { get { return left; } }
+
+ // Constants
+ private static readonly Vector2 _zero = new Vector2(0, 0);
+ private static readonly Vector2 _one = new Vector2(1, 1);
+ private static readonly Vector2 _negOne = new Vector2(-1, -1);
+ private static readonly Vector2 _inf = new Vector2(Mathf.Inf, Mathf.Inf);
+
+ private static readonly Vector2 _up = new Vector2(0, -1);
+ private static readonly Vector2 _down = new Vector2(0, 1);
+ private static readonly Vector2 _right = new Vector2(1, 0);
+ private static readonly Vector2 _left = new Vector2(-1, 0);
+
+ public static Vector2 Zero { get { return _zero; } }
+ public static Vector2 NegOne { get { return _negOne; } }
+ public static Vector2 One { get { return _one; } }
+ public static Vector2 Inf { get { return _inf; } }
+
+ public static Vector2 Up { get { return _up; } }
+ public static Vector2 Down { get { return _down; } }
+ public static Vector2 Right { get { return _right; } }
+ public static Vector2 Left { get { return _left; } }
// Constructors
public Vector2(real_t x, real_t y)
diff --git a/modules/mono/glue/cs_files/Vector3.cs b/modules/mono/glue/cs_files/Vector3.cs
index 085a4f0043..6fffe5e4d6 100644
--- a/modules/mono/glue/cs_files/Vector3.cs
+++ b/modules/mono/glue/cs_files/Vector3.cs
@@ -210,6 +210,11 @@ namespace Godot
);
}
+ public Vector3 Project(Vector3 onNormal)
+ {
+ return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
+ }
+
public Vector3 Reflect(Vector3 n)
{
#if DEBUG
@@ -272,27 +277,30 @@ namespace Godot
);
}
- private static readonly Vector3 zero = new Vector3 (0, 0, 0);
- private static readonly Vector3 one = new Vector3 (1, 1, 1);
- private static readonly Vector3 negOne = new Vector3 (-1, -1, -1);
+ // Constants
+ private static readonly Vector3 _zero = new Vector3(0, 0, 0);
+ private static readonly Vector3 _one = new Vector3(1, 1, 1);
+ private static readonly Vector3 _negOne = new Vector3(-1, -1, -1);
+ private static readonly Vector3 _inf = new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf);
- private static readonly Vector3 up = new Vector3 (0, 1, 0);
- private static readonly Vector3 down = new Vector3 (0, -1, 0);
- private static readonly Vector3 right = new Vector3 (1, 0, 0);
- private static readonly Vector3 left = new Vector3 (-1, 0, 0);
- private static readonly Vector3 forward = new Vector3 (0, 0, -1);
- private static readonly Vector3 back = new Vector3 (0, 0, 1);
-
- public static Vector3 Zero { get { return zero; } }
- public static Vector3 One { get { return one; } }
- public static Vector3 NegOne { get { return negOne; } }
+ private static readonly Vector3 _up = new Vector3(0, 1, 0);
+ private static readonly Vector3 _down = new Vector3(0, -1, 0);
+ private static readonly Vector3 _right = new Vector3(1, 0, 0);
+ private static readonly Vector3 _left = new Vector3(-1, 0, 0);
+ private static readonly Vector3 _forward = new Vector3(0, 0, -1);
+ private static readonly Vector3 _back = new Vector3(0, 0, 1);
+
+ public static Vector3 Zero { get { return _zero; } }
+ public static Vector3 One { get { return _one; } }
+ public static Vector3 NegOne { get { return _negOne; } }
+ public static Vector3 Inf { get { return _inf; } }
- public static Vector3 Up { get { return up; } }
- public static Vector3 Down { get { return down; } }
- public static Vector3 Right { get { return right; } }
- public static Vector3 Left { get { return left; } }
- public static Vector3 Forward { get { return forward; } }
- public static Vector3 Back { get { return back; } }
+ public static Vector3 Up { get { return _up; } }
+ public static Vector3 Down { get { return _down; } }
+ public static Vector3 Right { get { return _right; } }
+ public static Vector3 Left { get { return _left; } }
+ public static Vector3 Forward { get { return _forward; } }
+ public static Vector3 Back { get { return _back; } }
// Constructors
public Vector3(real_t x, real_t y, real_t z)
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index f564b93f8f..fadac941e9 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -148,7 +148,7 @@ void GDMono::initialize() {
ERR_FAIL_NULL(Engine::get_singleton());
- OS::get_singleton()->print("Mono: Initializing module...\n");
+ print_verbose("Mono: Initializing module...");
#ifdef DEBUG_METHODS_ENABLED
_initialize_and_check_api_hashes();
@@ -202,7 +202,7 @@ void GDMono::initialize() {
runtime_initialized = true;
- OS::get_singleton()->print("Mono: Runtime initialized\n");
+ print_verbose("Mono: Runtime initialized");
// mscorlib assembly MUST be present at initialization
ERR_EXPLAIN("Mono: Failed to load mscorlib assembly");
@@ -226,7 +226,7 @@ void GDMono::initialize() {
#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");
+ print_error("Mono: Debugger wait timeout");
#endif
_register_internal_calls();
@@ -256,7 +256,7 @@ void GDMono::initialize() {
metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true);
}
- OS::get_singleton()->print("Mono: Proceeding to unload scripts domain because of invalid API assemblies\n");
+ print_line("Mono: Proceeding to unload scripts domain because of invalid API assemblies.");
Error err = _unload_scripts_domain();
if (err != OK) {
@@ -269,11 +269,10 @@ void GDMono::initialize() {
}
}
#else
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n");
+ print_verbose("Mono: Glue disabled, ignoring script assemblies.");
#endif
- OS::get_singleton()->print("Mono: INITIALIZED\n");
+ print_verbose("Mono: INITIALIZED");
}
#ifndef MONO_GLUE_DISABLED
@@ -352,8 +351,7 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo
CRASH_COND(!r_assembly);
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print((String() + "Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...\n").utf8());
+ print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
MonoImageOpenStatus status = MONO_IMAGE_OK;
MonoAssembly *assembly = mono_assembly_load_full(p_aname, NULL, &status, p_refonly);
@@ -372,8 +370,7 @@ bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMo
*r_assembly = *stored_assembly;
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print(String("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path() + "\n").utf8());
+ print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
return true;
}
@@ -500,7 +497,7 @@ bool GDMono::_load_project_assembly() {
mono_assembly_set_main(project_assembly->get_assembly());
} else {
if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->printerr("Mono: Failed to load project assembly\n");
+ print_error("Mono: Failed to load project assembly");
}
return success;
@@ -510,13 +507,13 @@ bool GDMono::_load_api_assemblies() {
if (!_load_core_api_assembly()) {
if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->printerr("Mono: Failed to load Core API assembly\n");
+ print_error("Mono: Failed to load Core API assembly");
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");
+ print_error("Mono: Failed to load Editor API assembly");
return false;
}
#endif
@@ -593,9 +590,7 @@ 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");
- }
+ print_verbose("Mono: Loading scripts domain...");
scripts_domain = GDMonoUtils::create_domain("GodotEngine.ScriptsDomain");
@@ -611,9 +606,7 @@ 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");
- }
+ print_verbose("Mono: Unloading scripts domain...");
_GodotSharp::get_singleton()->_dispose_callback();
@@ -661,9 +654,7 @@ 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");
- }
+ print_verbose("Mono: Loading tools domain...");
tools_domain = GDMonoUtils::create_domain("GodotEngine.ToolsDomain");
@@ -728,8 +719,7 @@ Error GDMono::reload_scripts_domain() {
if (!_load_project_assembly())
return ERR_CANT_OPEN;
#else
- if (OS::get_singleton()->is_stdout_verbose())
- OS::get_singleton()->print("Mono: Glue disabled, ignoring script assemblies\n");
+ print_verbose("Mono: Glue disabled, ignoring script assemblies.");
#endif
return OK;
@@ -742,9 +732,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
String domain_name = mono_domain_get_friendly_name(p_domain);
- if (OS::get_singleton()->is_stdout_verbose()) {
- OS::get_singleton()->print(String("Mono: Unloading domain `" + domain_name + "`...\n").utf8());
- }
+ print_verbose("Mono: Unloading domain `" + domain_name + "`...");
if (mono_domain_get() != root_domain)
mono_domain_set(root_domain, true);
@@ -877,7 +865,7 @@ GDMono::~GDMono() {
GDMonoUtils::clear_cache();
- OS::get_singleton()->print("Mono: Runtime cleanup...\n");
+ print_verbose("Mono: Runtime cleanup...");
runtime_initialized = false;
mono_jit_cleanup(root_domain);
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 9d3bee2176..27ce39b6d7 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -42,8 +42,25 @@
#include "gd_mono_class.h"
bool GDMonoAssembly::no_search = false;
+bool GDMonoAssembly::in_preload = false;
+
Vector<String> GDMonoAssembly::search_dirs;
+void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, void *user_data) {
+
+ if (no_search)
+ return;
+
+ // If our search and preload hooks fail to load the assembly themselves, the mono runtime still might.
+ // Just do Assembly.LoadFrom("/Full/Path/On/Disk.dll");
+ // In this case, we wouldn't have the assembly known in GDMono, which causes crashes
+ // if any class inside the assembly is looked up by Godot.
+ // And causing a lookup like that is as easy as throwing an exception defined in it...
+ // No, we can't make the assembly load hooks smart enough because they get passed a MonoAssemblyName* only,
+ // not the disk path passed to say Assembly.LoadFrom().
+ _wrap_mono_assembly(assembly);
+}
+
MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) {
return GDMonoAssembly::_search_hook(aname, user_data, false);
}
@@ -111,6 +128,8 @@ MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, void *user_d
return res ? res->get_assembly() : NULL;
}
+static _THREAD_LOCAL_(MonoImage *) image_corlib_loading = NULL;
+
MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly) {
(void)user_data; // UNUSED
@@ -138,16 +157,38 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
}
}
+ {
+ // If we find the assembly here, we load it with `mono_assembly_load_from_full`,
+ // which in turn invokes load hooks before returning the MonoAssembly to us.
+ // One of the load hooks is `load_aot_module`. This hook can end up calling preload hooks
+ // again for the same assembly in certain in certain circumstances (the `do_load_image` part).
+ // If this is the case and we return NULL due to the no_search condition below,
+ // it will result in an internal crash later on. Therefore we need to return the assembly we didn't
+ // get yet from `mono_assembly_load_from_full`. Luckily we have the image, which already got it.
+ // This must be done here. If done in search hooks, it would cause `mono_assembly_load_from_full`
+ // to think another MonoAssembly for this assembly was already loaded, making it delete its own,
+ // when in fact both pointers were the same... This hooks thing is confusing.
+ if (image_corlib_loading) {
+ return mono_image_get_assembly(image_corlib_loading);
+ }
+ }
+
+ if (no_search)
+ return NULL;
+
+ no_search = true;
+ in_preload = true;
+
String name = mono_assembly_name_get_name(aname);
bool has_extension = name.ends_with(".dll");
+ GDMonoAssembly *res = NULL;
if (has_extension ? name == "mscorlib.dll" : name == "mscorlib") {
GDMonoAssembly **stored_assembly = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
if (stored_assembly)
return (*stored_assembly)->get_assembly();
String path;
- GDMonoAssembly *res = NULL;
for (int i = 0; i < search_dirs.size(); i++) {
const String &search_dir = search_dirs[i];
@@ -168,11 +209,12 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **asse
}
}
}
-
- return res ? res->get_assembly() : NULL;
}
- return NULL;
+ no_search = false;
+ in_preload = false;
+
+ return res ? res->get_assembly() : NULL;
}
GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly) {
@@ -192,12 +234,30 @@ GDMonoAssembly *GDMonoAssembly::_load_assembly_from(const String &p_name, const
return assembly;
}
+void GDMonoAssembly::_wrap_mono_assembly(MonoAssembly *assembly) {
+ String name = mono_assembly_name_get_name(mono_assembly_get_name(assembly));
+
+ MonoImage *image = mono_assembly_get_image(assembly);
+
+ GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, mono_image_get_filename(image)));
+ Error err = gdassembly->wrapper_for_image(image);
+
+ if (err != OK) {
+ memdelete(gdassembly);
+ ERR_FAIL();
+ }
+
+ MonoDomain *domain = mono_domain_get();
+ GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly);
+}
+
void GDMonoAssembly::initialize() {
mono_install_assembly_search_hook(&assembly_search_hook, NULL);
mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, NULL);
mono_install_assembly_preload_hook(&assembly_preload_hook, NULL);
mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, NULL);
+ mono_install_assembly_load_hook(&assembly_load_hook, NULL);
}
Error GDMonoAssembly::load(bool p_refonly) {
@@ -241,8 +301,16 @@ no_pdb:
#endif
+ bool is_corlib_preload = in_preload && name == "mscorlib";
+
+ if (is_corlib_preload)
+ image_corlib_loading = image;
+
assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, refonly);
+ if (is_corlib_preload)
+ image_corlib_loading = NULL;
+
ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN);
loaded = true;
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 5cf744a5a2..2c6d367fc6 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -89,8 +89,10 @@ class GDMonoAssembly {
#endif
static bool no_search;
+ static bool in_preload;
static Vector<String> search_dirs;
+ static void assembly_load_hook(MonoAssembly *assembly, void *user_data);
static MonoAssembly *assembly_search_hook(MonoAssemblyName *aname, void *user_data);
static MonoAssembly *assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data);
static MonoAssembly *assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
@@ -100,6 +102,7 @@ class GDMonoAssembly {
static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly);
static GDMonoAssembly *_load_assembly_from(const String &p_name, const String &p_path, bool p_refonly);
+ static void _wrap_mono_assembly(MonoAssembly *assembly);
friend class GDMono;
static void initialize();
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index eabea8dc3c..5224d309de 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -152,8 +152,7 @@ void GDMonoLog::initialize() {
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());
+ print_verbose("Mono: Logfile is " + log_file_path);
mono_trace_set_log_handler(gdmono_MonoLogCallback, this);
} else {
OS::get_singleton()->printerr("Mono: No log file, using default log handler\n");
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 911d629956..bebc3b863f 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -590,14 +590,14 @@ current_invoke_count = 0;
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **p_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)&p_exc);
+ MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)p_exc);
GD_MONO_END_RUNTIME_INVOKE;
return ret;
}
MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **p_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)&p_exc);
+ MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)p_exc);
GD_MONO_END_RUNTIME_INVOKE;
return ret;
}
diff --git a/modules/mono/utils/thread_local.cpp b/modules/mono/utils/thread_local.cpp
index ae9f130518..a0e28fca5f 100644
--- a/modules/mono/utils/thread_local.cpp
+++ b/modules/mono/utils/thread_local.cpp
@@ -69,7 +69,7 @@ struct ThreadLocalStorage::Impl {
#define _CALLBACK_FUNC_
#endif
- Impl(void (_CALLBACK_FUNC_ *p_destr_callback_func)(void *)) {
+ Impl(void(_CALLBACK_FUNC_ *p_destr_callback_func)(void *)) {
#ifdef WINDOWS_ENABLED
dwFlsIndex = FlsAlloc(p_destr_callback_func);
ERR_FAIL_COND(dwFlsIndex == FLS_OUT_OF_INDEXES);
@@ -95,7 +95,7 @@ void ThreadLocalStorage::set_value(void *p_value) const {
pimpl->set_value(p_value);
}
-void ThreadLocalStorage::alloc(void (_CALLBACK_FUNC_ *p_destr_callback)(void *)) {
+void ThreadLocalStorage::alloc(void(_CALLBACK_FUNC_ *p_destr_callback)(void *)) {
pimpl = memnew(ThreadLocalStorage::Impl(p_destr_callback));
}
diff --git a/modules/mono/utils/thread_local.h b/modules/mono/utils/thread_local.h
index 783e40dc01..84dae1d86b 100644
--- a/modules/mono/utils/thread_local.h
+++ b/modules/mono/utils/thread_local.h
@@ -76,7 +76,7 @@ struct ThreadLocalStorage {
void *get_value() const;
void set_value(void *p_value) const;
- void alloc(void (_CALLBACK_FUNC_ *p_dest_callback)(void *));
+ void alloc(void(_CALLBACK_FUNC_ *p_dest_callback)(void *));
void free();
private:
@@ -95,7 +95,6 @@ class ThreadLocal {
memdelete(static_cast<T *>(tls_data));
}
-
T *_tls_get_value() const {
void *tls_data = storage.get_value();
diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp
index f5d35714e1..6ec44023c1 100644
--- a/modules/pvr/texture_loader_pvr.cpp
+++ b/modules/pvr/texture_loader_pvr.cpp
@@ -93,7 +93,7 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path,
print_line("bmask: "+itos(bmask));
print_line("amask: "+itos(amask));
print_line("surfcount: "+itos(surfcount));
-*/
+ */
PoolVector<uint8_t> data;
data.resize(surfsize);
@@ -159,8 +159,6 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path,
if (mipmaps)
tex_flags |= Texture::FLAG_MIPMAPS;
- print_line("flip: " + itos(flags & PVR_VFLIP));
-
Ref<Image> image = memnew(Image(width, height, mipmaps, format, data));
ERR_FAIL_COND_V(image->empty(), RES());
@@ -646,12 +644,6 @@ static void decompress_pvrtc(PVRTCBlock *p_comp_img, const int p_2bit, const int
static void _pvrtc_decompress(Image *p_img) {
- /*
- static void decompress_pvrtc(const void *p_comp_img, const int p_2bit, const int p_width, const int p_height, unsigned char* p_dst) {
- decompress_pvrtc((PVRTCBlock*)p_comp_img,p_2bit,p_width,p_height,1,p_dst);
- }
- */
-
ERR_FAIL_COND(p_img->get_format() != Image::FORMAT_PVRTC2 && p_img->get_format() != Image::FORMAT_PVRTC2A && p_img->get_format() != Image::FORMAT_PVRTC4 && p_img->get_format() != Image::FORMAT_PVRTC4A);
bool _2bit = (p_img->get_format() == Image::FORMAT_PVRTC2 || p_img->get_format() == Image::FORMAT_PVRTC2A);
@@ -665,12 +657,6 @@ static void _pvrtc_decompress(Image *p_img) {
decompress_pvrtc((PVRTCBlock *)r.ptr(), _2bit, p_img->get_width(), p_img->get_height(), 0, (unsigned char *)w.ptr());
- /*
- for(int i=0;i<newdata.size();i++) {
- print_line(itos(w[i]));
- }
- */
-
w = PoolVector<uint8_t>::Write();
r = PoolVector<uint8_t>::Read();
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp
index 0cf24dd8d8..653dd82351 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_compress_squish.cpp
@@ -32,12 +32,6 @@
#include "print_string.h"
-#if defined(__SSE2__)
-#define SQUISH_USE_SSE 2
-#elif defined(__SSE__)
-#define SQUISH_USE_SSE 1
-#endif
-
#include <squish.h>
void image_decompress_squish(Image *p_image) {
@@ -46,7 +40,7 @@ void image_decompress_squish(Image *p_image) {
Image::Format target_format = Image::FORMAT_RGBA8;
PoolVector<uint8_t> data;
- int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
+ int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->get_mipmap_count();
data.resize(target_size);
@@ -65,7 +59,7 @@ void image_decompress_squish(Image *p_image) {
} else if (p_image->get_format() == Image::FORMAT_RGTC_RG) {
squish_flags = squish::kBc5;
} else {
- print_line("Can't decompress unknown format: " + itos(p_image->get_format()));
+ ERR_EXPLAIN("Squish: Can't decompress unknown format: " + itos(p_image->get_format()));
ERR_FAIL_COND(true);
return;
}
@@ -81,7 +75,7 @@ void image_decompress_squish(Image *p_image) {
p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}
-void image_compress_squish(Image *p_image, Image::CompressSource p_source) {
+void image_compress_squish(Image *p_image, float p_lossy_quality, Image::CompressSource p_source) {
if (p_image->get_format() >= Image::FORMAT_DXT1)
return; //do not compress, already compressed
@@ -92,10 +86,43 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) {
if (p_image->get_format() <= Image::FORMAT_RGBA8) {
int squish_comp = squish::kColourRangeFit;
+
+ if (p_lossy_quality > 0.85)
+ squish_comp = squish::kColourIterativeClusterFit;
+ else if (p_lossy_quality > 0.75)
+ squish_comp = squish::kColourClusterFit;
+
Image::Format target_format = Image::FORMAT_RGBA8;
Image::DetectChannels dc = p_image->get_detected_channels();
+ if (p_source == Image::COMPRESS_SOURCE_LAYERED) {
+ //keep what comes in
+ switch (p_image->get_format()) {
+ case Image::FORMAT_L8: {
+ dc = Image::DETECTED_L;
+ } break;
+ case Image::FORMAT_LA8: {
+ dc = Image::DETECTED_LA;
+ } break;
+ case Image::FORMAT_R8: {
+ dc = Image::DETECTED_R;
+ } break;
+ case Image::FORMAT_RG8: {
+ dc = Image::DETECTED_RG;
+ } break;
+ case Image::FORMAT_RGB8: {
+ dc = Image::DETECTED_RGB;
+ } break;
+ case Image::FORMAT_RGBA8:
+ case Image::FORMAT_RGBA4444:
+ case Image::FORMAT_RGBA5551: {
+ dc = Image::DETECTED_RGBA;
+ } break;
+ default: {}
+ }
+ }
+
p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
if (p_source == Image::COMPRESS_SOURCE_SRGB && (dc == Image::DETECTED_R || dc == Image::DETECTED_RG)) {
@@ -148,7 +175,7 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) {
}
PoolVector<uint8_t> data;
- int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0);
+ int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
data.resize(target_size);
int shift = Image::get_format_pixel_rshift(target_format);
diff --git a/modules/squish/image_compress_squish.h b/modules/squish/image_compress_squish.h
index c022063fe5..6da947beea 100644
--- a/modules/squish/image_compress_squish.h
+++ b/modules/squish/image_compress_squish.h
@@ -33,7 +33,7 @@
#include "image.h"
-void image_compress_squish(Image *p_image, Image::CompressSource p_source);
+void image_compress_squish(Image *p_image, float p_lossy_quality, Image::CompressSource p_source);
void image_decompress_squish(Image *p_image);
#endif // IMAGE_COMPRESS_SQUISH_H
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
index c95a8ac2dd..0e533d3978 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
@@ -208,8 +208,6 @@ void AudioStreamOGGVorbis::set_data(const PoolVector<uint8_t> &p_data) {
//does this work? (it's less mem..)
//decode_mem_size = ogg_alloc.alloc_buffer_length_in_bytes + info.setup_memory_required + info.temp_memory_required + info.max_frame_size;
- //print_line("succeeded "+itos(ogg_alloc.alloc_buffer_length_in_bytes)+" setup "+itos(info.setup_memory_required)+" setup temp "+itos(info.setup_temp_memory_required)+" temp "+itos(info.temp_memory_required)+" maxframe"+itos(info.max_frame_size));
-
length = stb_vorbis_stream_length_in_seconds(ogg_stream);
stb_vorbis_close(ogg_stream);
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 881808873b..68087ac01f 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -387,7 +387,6 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
thread_sem->post();
#endif
- //print_line("play "+rtos(p_delta));
time += p_delta;
if (videobuf_time > get_time()) {
@@ -442,16 +441,8 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
int tr = vorbis_synthesis_read(&vd, ret - to_read);
- if (vd.granulepos >= 0) {
- //print_line("wrote: "+itos(audio_frames_wrote)+" gpos: "+itos(vd.granulepos));
- }
-
- //print_line("mix audio!");
-
audio_frames_wrote += ret - to_read;
- //print_line("AGP: "+itos(vd.granulepos)+" added "+itos(ret-to_read));
-
} else {
/* no pending audio; is there a pending packet to decode? */
@@ -460,7 +451,6 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
vorbis_synthesis_blockin(&vd, &vb);
}
} else { /* we need more data; break out to suck in another page */
- //printf("need moar data\n");
break;
};
}
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 7cee1b491b..1aba3f56da 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -163,7 +163,6 @@ public:
class VideoStreamTheora : public VideoStream {
GDCLASS(VideoStreamTheora, VideoStream);
- RES_BASE_EXTENSION("ogv");
String file;
int audio_track;
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index de9b3d5a91..bbdec7195f 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -2415,7 +2415,7 @@ void VisualScriptLanguage::make_template(const String &p_class_name, const Strin
script->set_instance_base_type(p_base_class_name);
}
-bool VisualScriptLanguage::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, Set<int> *r_safe_lines) const {
+bool VisualScriptLanguage::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, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
return false;
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index 2ad72a40c0..13a8b909b0 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -564,7 +564,7 @@ public:
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);
- 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, Set<int> *r_safe_lines = NULL) 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, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 73b6d702c1..8e98b08b22 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1144,15 +1144,12 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
case VisualScriptBuiltinFunc::TEXT_PRINTERR: {
String str = *p_inputs[0];
-
- //str+="\n";
print_error(str);
} break;
case VisualScriptBuiltinFunc::TEXT_PRINTRAW: {
- String str = *p_inputs[0];
- //str+="\n";
+ String str = *p_inputs[0];
OS::get_singleton()->print("%s", str.utf8().get_data());
} break;
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index ef40af686c..4471fbd0c4 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -882,7 +882,6 @@ void VisualScriptEditor::_member_selected() {
ERR_FAIL_COND(!ti);
selected = ti->get_metadata(0);
- //print_line("selected: "+String(selected));
if (ti->get_parent() == members->get_root()->get_children()) {
@@ -3032,7 +3031,8 @@ void VisualScriptEditor::_node_filter_changed(const String &p_text) {
void VisualScriptEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
- node_filter->add_icon_override("right_icon", Control::get_icon("Search", "EditorIcons"));
+ node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons"));
+ node_filter->set_clear_button_enabled(true);
variable_editor->connect("changed", this, "_update_members");
signal_editor->connect("changed", this, "_update_members");
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index ad886bc758..f926d4e2eb 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -394,7 +394,6 @@ void VisualScriptFunctionCall::_update_method_cache() {
}
}
- //print_line("BASE: "+String(type)+" FUNC: "+String(function));
MethodBind *mb = ClassDB::get_method(type, function);
if (mb) {
use_default_args = mb->get_default_argument_count();
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index a6ec36d364..d499512d93 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -1663,7 +1663,7 @@ Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const {
class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance {
public:
- int value;
+ Variant value;
bool valid;
//virtual int get_working_memory_size() const { return 0; }
@@ -1682,7 +1682,7 @@ public:
VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instance(VisualScriptInstance *p_instance) {
VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant);
- instance->value = Variant::get_numeric_constant_value(type, name, &instance->valid);
+ instance->value = Variant::get_constant_value(type, name, &instance->valid);
return instance;
}
@@ -1691,7 +1691,7 @@ void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) c
if (property.name == "constant") {
List<StringName> constants;
- Variant::get_numeric_constants_for_type(type, &constants);
+ Variant::get_constants_for_type(type, &constants);
if (constants.size() == 0) {
property.usage = 0;
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index e4dfc5fe45..f79c81ad88 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -285,7 +285,6 @@ void VisualScriptPropertySelector::_update_search() {
Ref<Texture> icon;
script_methods = false;
- print_line("name: " + E->get().name);
String rep = E->get().name.replace("*", "");
if (E->get().name == "*Script Methods") {
icon = get_icon("Script", "EditorIcons");
diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h
index 08be50846d..dcf88092c5 100644
--- a/modules/webm/video_stream_webm.h
+++ b/modules/webm/video_stream_webm.h
@@ -109,7 +109,6 @@ private:
class VideoStreamWebm : public VideoStream {
GDCLASS(VideoStreamWebm, VideoStream);
- RES_BASE_EXTENSION("webm");
String file;
int audio_track;
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index 15a88773e7..c0985b3245 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -7,87 +7,88 @@ Import('env_modules')
env_lws = env_modules.Clone()
-thirdparty_dir = "#thirdparty/libwebsockets/"
-helper_dir = "win32helpers/"
-thirdparty_sources = [
-
- "core/alloc.c",
- "core/context.c",
- "core/libwebsockets.c",
- "core/output.c",
- "core/pollfd.c",
- "core/service.c",
-
- "event-libs/poll/poll.c",
-
- "misc/base64-decode.c",
- "misc/lejp.c",
- "misc/sha-1.c",
-
- "roles/h1/ops-h1.c",
- "roles/http/header.c",
- "roles/http/client/client.c",
- "roles/http/client/client-handshake.c",
- "roles/http/server/fops-zip.c",
- "roles/http/server/lejp-conf.c",
- "roles/http/server/parsers.c",
- "roles/http/server/server.c",
- "roles/listen/ops-listen.c",
- "roles/pipe/ops-pipe.c",
- "roles/raw/ops-raw.c",
-
- "roles/ws/client-ws.c",
- "roles/ws/client-parser-ws.c",
- "roles/ws/ops-ws.c",
- "roles/ws/server-ws.c",
-
- "tls/tls.c",
- "tls/tls-client.c",
- "tls/tls-server.c",
-
- "tls/mbedtls/wrapper/library/ssl_cert.c",
- "tls/mbedtls/wrapper/library/ssl_pkey.c",
- "tls/mbedtls/wrapper/library/ssl_stack.c",
- "tls/mbedtls/wrapper/library/ssl_methods.c",
- "tls/mbedtls/wrapper/library/ssl_lib.c",
- "tls/mbedtls/wrapper/library/ssl_x509.c",
- "tls/mbedtls/wrapper/platform/ssl_port.c",
- "tls/mbedtls/wrapper/platform/ssl_pm.c",
- "tls/mbedtls/lws-genhash.c",
- "tls/mbedtls/mbedtls-client.c",
- "tls/mbedtls/lws-genrsa.c",
- "tls/mbedtls/ssl.c",
- "tls/mbedtls/mbedtls-server.c"
-]
-
-if env_lws["platform"] == "android": # Builtin getifaddrs
- thirdparty_sources += ["misc/getifaddrs.c"]
-
-if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": # Winsock
- thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"]
-else: # Unix socket
- thirdparty_sources += ["plat/lws-plat-unix.c"]
-
-
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-if env_lws["platform"] == "javascript": # No need to add third party libraries at all
- pass
-else:
- env_lws.add_source_files(env.modules_sources, thirdparty_sources)
- env_lws.Append(CPPPATH=[thirdparty_dir])
-
- wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]]
- env_lws.Prepend(CPPPATH=wrapper_includes)
-
- if env['builtin_mbedtls']:
- mbedtls_includes = "#thirdparty/mbedtls/include"
- env_lws.Prepend(CPPPATH=[mbedtls_includes])
-
- if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp":
- env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir])
-
- if env_lws["platform"] == "uwp":
- env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"])
+if env['builtin_libwebsockets']:
+ thirdparty_dir = "#thirdparty/libwebsockets/"
+ helper_dir = "win32helpers/"
+ thirdparty_sources = [
+
+ "core/alloc.c",
+ "core/context.c",
+ "core/libwebsockets.c",
+ "core/output.c",
+ "core/pollfd.c",
+ "core/service.c",
+
+ "event-libs/poll/poll.c",
+
+ "misc/base64-decode.c",
+ "misc/lejp.c",
+ "misc/sha-1.c",
+
+ "roles/h1/ops-h1.c",
+ "roles/http/header.c",
+ "roles/http/client/client.c",
+ "roles/http/client/client-handshake.c",
+ "roles/http/server/fops-zip.c",
+ "roles/http/server/lejp-conf.c",
+ "roles/http/server/parsers.c",
+ "roles/http/server/server.c",
+ "roles/listen/ops-listen.c",
+ "roles/pipe/ops-pipe.c",
+ "roles/raw/ops-raw.c",
+
+ "roles/ws/client-ws.c",
+ "roles/ws/client-parser-ws.c",
+ "roles/ws/ops-ws.c",
+ "roles/ws/server-ws.c",
+
+ "tls/tls.c",
+ "tls/tls-client.c",
+ "tls/tls-server.c",
+
+ "tls/mbedtls/wrapper/library/ssl_cert.c",
+ "tls/mbedtls/wrapper/library/ssl_pkey.c",
+ "tls/mbedtls/wrapper/library/ssl_stack.c",
+ "tls/mbedtls/wrapper/library/ssl_methods.c",
+ "tls/mbedtls/wrapper/library/ssl_lib.c",
+ "tls/mbedtls/wrapper/library/ssl_x509.c",
+ "tls/mbedtls/wrapper/platform/ssl_port.c",
+ "tls/mbedtls/wrapper/platform/ssl_pm.c",
+ "tls/mbedtls/lws-genhash.c",
+ "tls/mbedtls/mbedtls-client.c",
+ "tls/mbedtls/lws-genrsa.c",
+ "tls/mbedtls/ssl.c",
+ "tls/mbedtls/mbedtls-server.c"
+ ]
+
+ if env_lws["platform"] == "android": # Builtin getifaddrs
+ thirdparty_sources += ["misc/getifaddrs.c"]
+
+ if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": # Winsock
+ thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"]
+ else: # Unix socket
+ thirdparty_sources += ["plat/lws-plat-unix.c"]
+
+
+ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+ if env_lws["platform"] == "javascript": # No need to add third party libraries at all
+ pass
+ else:
+ env_lws.add_source_files(env.modules_sources, thirdparty_sources)
+ env_lws.Append(CPPPATH=[thirdparty_dir])
+
+ wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]]
+ env_lws.Prepend(CPPPATH=wrapper_includes)
+
+ if env['builtin_mbedtls']:
+ mbedtls_includes = "#thirdparty/mbedtls/include"
+ env_lws.Prepend(CPPPATH=[mbedtls_includes])
+
+ if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp":
+ env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir])
+
+ if env_lws["platform"] == "uwp":
+ env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"])
env_lws.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp
index 06f97aaf05..ac31daa108 100644
--- a/modules/websocket/lws_client.cpp
+++ b/modules/websocket/lws_client.cpp
@@ -127,11 +127,6 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi
case LWS_CALLBACK_CLIENT_ESTABLISHED:
peer->set_wsi(wsi);
peer_data->peer_id = 0;
- peer_data->in_size = 0;
- peer_data->in_count = 0;
- peer_data->out_count = 0;
- peer_data->rbw.resize(16);
- peer_data->rbr.resize(16);
peer_data->force_close = false;
_on_connect(lws_get_protocol(wsi)->name);
break;
@@ -142,10 +137,6 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi
return -1; // we should close the connection (would probably happen anyway)
case LWS_CALLBACK_CLIENT_CLOSED:
- peer_data->in_count = 0;
- peer_data->out_count = 0;
- peer_data->rbw.resize(0);
- peer_data->rbr.resize(0);
peer->close();
destroy_context();
_on_disconnect();
diff --git a/modules/websocket/lws_peer.cpp b/modules/websocket/lws_peer.cpp
index 96acb99cc4..0989357258 100644
--- a/modules/websocket/lws_peer.cpp
+++ b/modules/websocket/lws_peer.cpp
@@ -41,6 +41,10 @@
#include "drivers/unix/socket_helpers.h"
void LWSPeer::set_wsi(struct lws *p_wsi) {
+ ERR_FAIL_COND(wsi != NULL);
+
+ rbw.resize(16);
+ rbr.resize(16);
wsi = p_wsi;
};
@@ -57,24 +61,24 @@ Error LWSPeer::read_wsi(void *in, size_t len) {
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi));
- uint32_t size = peer_data->in_size;
+ uint32_t size = in_size;
uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1;
- if (peer_data->rbr.space_left() < len + 5) {
+ if (rbr.space_left() < len + 5) {
ERR_EXPLAIN("Buffer full! Dropping data");
ERR_FAIL_V(FAILED);
}
- copymem(&(peer_data->input_buffer[size]), in, len);
+ copymem(&(input_buffer[size]), in, len);
size += len;
- peer_data->in_size = size;
+ in_size = size;
if (lws_is_final_fragment(wsi)) {
- peer_data->rbr.write((uint8_t *)&size, 4);
- peer_data->rbr.write((uint8_t *)&is_string, 1);
- peer_data->rbr.write(peer_data->input_buffer, size);
- peer_data->in_count++;
- peer_data->in_size = 0;
+ rbr.write((uint8_t *)&size, 4);
+ rbr.write((uint8_t *)&is_string, 1);
+ rbr.write(input_buffer, size);
+ in_count++;
+ in_size = 0;
}
return OK;
@@ -86,26 +90,26 @@ Error LWSPeer::write_wsi() {
PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi));
PoolVector<uint8_t> tmp;
- int left = peer_data->rbw.data_left();
+ int left = rbw.data_left();
uint32_t to_write = 0;
- if (left == 0 || peer_data->out_count == 0)
+ if (left == 0 || out_count == 0)
return OK;
- peer_data->rbw.read((uint8_t *)&to_write, 4);
- peer_data->out_count--;
+ rbw.read((uint8_t *)&to_write, 4);
+ out_count--;
if (left < to_write) {
- peer_data->rbw.advance_read(left);
+ rbw.advance_read(left);
return FAILED;
}
tmp.resize(LWS_PRE + to_write);
- peer_data->rbw.read(&(tmp.write()[LWS_PRE]), to_write);
+ rbw.read(&(tmp.write()[LWS_PRE]), to_write);
lws_write(wsi, &(tmp.write()[LWS_PRE]), to_write, (enum lws_write_protocol)write_mode);
tmp.resize(0);
- if (peer_data->out_count > 0)
+ if (out_count > 0)
lws_callback_on_writable(wsi); // we want to write more!
return OK;
@@ -116,9 +120,9 @@ Error LWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
PeerData *peer_data = (PeerData *)lws_wsi_user(wsi);
- peer_data->rbw.write((uint8_t *)&p_buffer_size, 4);
- peer_data->rbw.write(p_buffer, MIN(p_buffer_size, peer_data->rbw.space_left()));
- peer_data->out_count++;
+ rbw.write((uint8_t *)&p_buffer_size, 4);
+ rbw.write(p_buffer, MIN(p_buffer_size, rbw.space_left()));
+ out_count++;
lws_callback_on_writable(wsi); // notify that we want to write
return OK;
@@ -130,7 +134,7 @@ Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
PeerData *peer_data = (PeerData *)lws_wsi_user(wsi);
- if (peer_data->in_count == 0)
+ if (in_count == 0)
return ERR_UNAVAILABLE;
uint32_t to_read = 0;
@@ -138,17 +142,17 @@ Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
uint8_t is_string = 0;
r_buffer_size = 0;
- peer_data->rbr.read((uint8_t *)&to_read, 4);
- peer_data->in_count--;
- left = peer_data->rbr.data_left();
+ rbr.read((uint8_t *)&to_read, 4);
+ in_count--;
+ left = rbr.data_left();
if (left < to_read + 1) {
- peer_data->rbr.advance_read(left);
+ rbr.advance_read(left);
return FAILED;
}
- peer_data->rbr.read(&is_string, 1);
- peer_data->rbr.read(packet_buffer, to_read);
+ rbr.read(&is_string, 1);
+ rbr.read(packet_buffer, to_read);
*r_buffer = packet_buffer;
r_buffer_size = to_read;
_was_string = is_string;
@@ -161,7 +165,7 @@ int LWSPeer::get_available_packet_count() const {
if (!is_connected_to_host())
return 0;
- return ((PeerData *)lws_wsi_user(wsi))->in_count;
+ return in_count;
};
bool LWSPeer::was_string_packet() const {
@@ -176,12 +180,17 @@ bool LWSPeer::is_connected_to_host() const {
void LWSPeer::close() {
if (wsi != NULL) {
- struct lws *tmp = wsi;
PeerData *data = ((PeerData *)lws_wsi_user(wsi));
data->force_close = true;
- wsi = NULL;
- lws_callback_on_writable(tmp); // notify that we want to disconnect
+ lws_callback_on_writable(wsi); // notify that we want to disconnect
}
+ wsi = NULL;
+ rbw.resize(0);
+ rbr.resize(0);
+ in_count = 0;
+ in_size = 0;
+ out_count = 0;
+ _was_string = false;
};
IP_Address LWSPeer::get_connected_host() const {
@@ -228,8 +237,8 @@ uint16_t LWSPeer::get_connected_port() const {
LWSPeer::LWSPeer() {
wsi = NULL;
- _was_string = false;
write_mode = WRITE_MODE_BINARY;
+ close();
};
LWSPeer::~LWSPeer() {
diff --git a/modules/websocket/lws_peer.h b/modules/websocket/lws_peer.h
index e96b38b168..d7d46e3076 100644
--- a/modules/websocket/lws_peer.h
+++ b/modules/websocket/lws_peer.h
@@ -57,14 +57,15 @@ public:
struct PeerData {
uint32_t peer_id;
bool force_close;
- RingBuffer<uint8_t> rbw;
- RingBuffer<uint8_t> rbr;
- mutable uint8_t input_buffer[PACKET_BUFFER_SIZE];
- uint32_t in_size;
- int in_count;
- int out_count;
};
+ RingBuffer<uint8_t> rbw;
+ RingBuffer<uint8_t> rbr;
+ uint8_t input_buffer[PACKET_BUFFER_SIZE];
+ uint32_t in_size;
+ int in_count;
+ int out_count;
+
virtual int get_available_packet_count() const;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
diff --git a/modules/websocket/lws_server.cpp b/modules/websocket/lws_server.cpp
index 8d13dc7a98..bb724bce9c 100644
--- a/modules/websocket/lws_server.cpp
+++ b/modules/websocket/lws_server.cpp
@@ -92,11 +92,6 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi
_peer_map[id] = peer;
peer_data->peer_id = id;
- peer_data->in_size = 0;
- peer_data->in_count = 0;
- peer_data->out_count = 0;
- peer_data->rbw.resize(16);
- peer_data->rbr.resize(16);
peer_data->force_close = false;
_on_connect(id, lws_get_protocol(wsi)->name);
@@ -111,10 +106,6 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi
_peer_map[id]->close();
_peer_map.erase(id);
}
- peer_data->in_count = 0;
- peer_data->out_count = 0;
- peer_data->rbr.resize(0);
- peer_data->rbw.resize(0);
_on_disconnect(id);
return 0; // we can end here
}