diff options
Diffstat (limited to 'modules')
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 } |