diff options
Diffstat (limited to 'modules')
38 files changed, 782 insertions, 307 deletions
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 632682a15d..9144a781a0 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -625,14 +625,14 @@ uint32_t BulletPhysicsServer3D::body_get_user_flags(RID p_body) const { return 0; } -void BulletPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, float p_value) { +void BulletPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND(!body); body->set_param(p_param, p_value); } -float BulletPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const { +real_t BulletPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, 0); @@ -807,11 +807,11 @@ int BulletPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const { return body->get_max_collisions_detection(); } -void BulletPhysicsServer3D::body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) { +void BulletPhysicsServer3D::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) { // Not supported by bullet and even Godot } -float BulletPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_body) const { +real_t BulletPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_body) const { // Not supported by bullet and even Godot return 0.; } @@ -862,7 +862,7 @@ bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform &p_from return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes); } -int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) { +int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, 0); ERR_FAIL_COND_V(!body->get_space(), 0); @@ -1221,7 +1221,7 @@ RID BulletPhysicsServer3D::joint_create_pin(RID p_body_A, const Vector3 &p_local CreateThenReturnRID(joint_owner, joint); } -void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) { +void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); ERR_FAIL_COND(joint->get_type() != JOINT_PIN); @@ -1229,7 +1229,7 @@ void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_par pin_joint->set_param(p_param, p_value); } -float BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { +real_t BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0); @@ -1309,7 +1309,7 @@ RID BulletPhysicsServer3D::joint_create_hinge_simple(RID p_body_A, const Vector3 CreateThenReturnRID(joint_owner, joint); } -void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) { +void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); ERR_FAIL_COND(joint->get_type() != JOINT_HINGE); @@ -1317,7 +1317,7 @@ void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p hinge_joint->set_param(p_param, p_value); } -float BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const { +real_t BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0); @@ -1361,7 +1361,7 @@ RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform &p_ CreateThenReturnRID(joint_owner, joint); } -void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) { +void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER); @@ -1369,7 +1369,7 @@ void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam slider_joint->set_param(p_param, p_value); } -float BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const { +real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); ERR_FAIL_COND_V(joint->get_type() != JOINT_SLIDER, 0); @@ -1395,7 +1395,7 @@ RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform CreateThenReturnRID(joint_owner, joint); } -void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) { +void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST); @@ -1403,7 +1403,7 @@ void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJoi coneTwist_joint->set_param(p_param, p_value); } -float BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const { +real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0.); ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0.); @@ -1431,7 +1431,7 @@ RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transfo CreateThenReturnRID(joint_owner, joint); } -void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) { +void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND(!joint); ERR_FAIL_COND(joint->get_type() != JOINT_6DOF); @@ -1439,7 +1439,7 @@ void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::A generic_6dof_joint->set_param(p_axis, p_param, p_value); } -float BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) { +real_t BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) { JointBullet *joint = joint_owner.getornull(p_joint); ERR_FAIL_COND_V(!joint, 0); ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0); @@ -1525,7 +1525,7 @@ void BulletPhysicsServer3D::init() { BulletPhysicsDirectBodyState3D::initSingleton(); } -void BulletPhysicsServer3D::step(float p_deltaTime) { +void BulletPhysicsServer3D::step(real_t p_deltaTime) { if (!active) { return; } diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index b5dc84c8f5..f2740c9c75 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -207,8 +207,8 @@ public: /// This is not supported by physics server virtual uint32_t body_get_user_flags(RID p_body) const override; - virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) override; - virtual float body_get_param(RID p_body, BodyParameter p_param) const override; + virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override; + virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override; virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) override; virtual real_t body_get_kinematic_safe_margin(RID p_body) const override; @@ -241,8 +241,8 @@ public: virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override; virtual int body_get_max_contacts_reported(RID p_body) const override; - virtual void body_set_contacts_reported_depth_threshold(RID p_body, float p_threshold) override; - virtual float body_get_contacts_reported_depth_threshold(RID p_body) const override; + virtual void body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) override; + virtual real_t body_get_contacts_reported_depth_threshold(RID p_body) const override; virtual void body_set_omit_force_integration(RID p_body, bool p_omit) override; virtual bool body_is_omitting_force_integration(RID p_body) const override; @@ -256,7 +256,7 @@ public: virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; - virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001) override; + virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; /* SOFT BODY API */ @@ -337,8 +337,8 @@ public: virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) override; - virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, float p_value) override; - virtual float pin_joint_get_param(RID p_joint, PinJointParam p_param) const override; + virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) override; + virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const override; virtual void pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) override; virtual Vector3 pin_joint_get_local_a(RID p_joint) const override; @@ -349,8 +349,8 @@ public: virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) override; virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override; - virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, float p_value) override; - virtual float hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override; + virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override; + virtual real_t hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const override; virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) override; virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override; @@ -358,20 +358,20 @@ public: /// Reference frame is A virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; - virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, float p_value) override; - virtual float slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override; + virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override; + virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override; /// Reference frame is A virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; - virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, float p_value) override; - virtual float cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override; + virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override; + virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override; /// Reference frame is A virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; - virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, float p_value) override; - virtual float generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) override; + virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) override; + virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) override; virtual void generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) override; virtual bool generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) override; @@ -393,7 +393,7 @@ public: } virtual void init() override; - virtual void step(float p_deltaTime) override; + virtual void step(real_t p_deltaTime) override; virtual void flush_queries() override; virtual void finish() override; diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 4763098584..a5093afe9d 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -56,11 +56,11 @@ Vector3 BulletPhysicsDirectBodyState3D::get_total_gravity() const { return gVec; } -float BulletPhysicsDirectBodyState3D::get_total_angular_damp() const { +real_t BulletPhysicsDirectBodyState3D::get_total_angular_damp() const { return body->btBody->getAngularDamping(); } -float BulletPhysicsDirectBodyState3D::get_total_linear_damp() const { +real_t BulletPhysicsDirectBodyState3D::get_total_linear_damp() const { return body->btBody->getLinearDamping(); } @@ -74,7 +74,7 @@ Basis BulletPhysicsDirectBodyState3D::get_principal_inertia_axes() const { return Basis(); } -float BulletPhysicsDirectBodyState3D::get_inverse_mass() const { +real_t BulletPhysicsDirectBodyState3D::get_inverse_mass() const { return body->btBody->getInvMass(); } @@ -158,7 +158,7 @@ Vector3 BulletPhysicsDirectBodyState3D::get_contact_local_normal(int p_contact_i return body->collisions[p_contact_idx].hitNormal; } -float BulletPhysicsDirectBodyState3D::get_contact_impulse(int p_contact_idx) const { +real_t BulletPhysicsDirectBodyState3D::get_contact_impulse(int p_contact_idx) const { return body->collisions[p_contact_idx].appliedImpulse; } @@ -412,7 +412,7 @@ void RigidBodyBullet::on_collision_checker_end() { isTransformChanged = btBody->isActive() && !btBody->isStaticOrKinematicObject(); } -bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) { +bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const real_t &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) { if (collisionsCount >= maxCollisionsDetection) { return false; } @@ -710,12 +710,12 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const { } void RigidBodyBullet::reload_axis_lock() { - btBody->setLinearFactor(btVector3(float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)))); + btBody->setLinearFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)))); if (PhysicsServer3D::BODY_MODE_CHARACTER == mode) { /// When character angular is always locked btBody->setAngularFactor(btVector3(0., 0., 0.)); } else { - btBody->setAngularFactor(btVector3(float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y)), float(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z)))); + btBody->setAngularFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z)))); } } diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index fc3f2db796..57b80cf50c 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -89,13 +89,13 @@ private: public: virtual Vector3 get_total_gravity() const override; - virtual float get_total_angular_damp() const override; - virtual float get_total_linear_damp() const override; + virtual real_t get_total_angular_damp() const override; + virtual real_t get_total_linear_damp() const override; virtual Vector3 get_center_of_mass() const override; virtual Basis get_principal_inertia_axes() const override; // get the mass - virtual float get_inverse_mass() const override; + virtual real_t get_inverse_mass() const override; // get density of this body space virtual Vector3 get_inverse_inertia() const override; // get density of this body space @@ -124,7 +124,7 @@ public: virtual Vector3 get_contact_local_position(int p_contact_idx) const override; virtual Vector3 get_contact_local_normal(int p_contact_idx) const override; - virtual float get_contact_impulse(int p_contact_idx) const override; + virtual real_t get_contact_impulse(int p_contact_idx) const override; virtual int get_contact_local_shape(int p_contact_idx) const override; virtual RID get_contact_collider(int p_contact_idx) const override; @@ -150,7 +150,7 @@ public: Vector3 hitLocalLocation; Vector3 hitWorldLocation; Vector3 hitNormal; - float appliedImpulse; + real_t appliedImpulse; }; struct ForceIntegrationCallback { @@ -264,7 +264,7 @@ public: } bool can_add_collision() { return collisionsCount < maxCollisionsDetection; } - bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index); + bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const real_t &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index); bool was_colliding(RigidBodyBullet *p_other_object); void set_activation_state(bool p_active); diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index cc2ec28a9e..82876ab77c 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -480,7 +480,11 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { Vector<real_t> l_heights; Variant l_heights_v = d["heights"]; +#ifdef REAL_T_IS_DOUBLE + if (l_heights_v.get_type() == Variant::PACKED_FLOAT64_ARRAY) { +#else if (l_heights_v.get_type() == Variant::PACKED_FLOAT32_ARRAY) { +#endif // Ready-to-use heights can be passed l_heights = l_heights_v; @@ -503,7 +507,7 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { real_t *w = l_heights.ptrw(); const uint8_t *r = im_data.ptr(); - float *rp = (float *)r; + real_t *rp = (real_t *)r; // At this point, `rp` could be used directly for Bullet, but I don't know how safe it would be. for (int i = 0; i < l_heights.size(); ++i) { @@ -511,7 +515,11 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { } } else { +#ifdef REAL_T_IS_DOUBLE + ERR_FAIL_MSG("Expected PackedFloat64Array or float Image."); +#else ERR_FAIL_MSG("Expected PackedFloat32Array or float Image."); +#endif } ERR_FAIL_COND(l_width <= 0); diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index d7dd11d2a5..79a5fdb3d2 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -117,7 +117,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V } } -int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return 0; } @@ -152,7 +152,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { +bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { r_closest_safe = 0.0f; r_closest_unsafe = 0.0f; btVector3 bt_motion; @@ -214,7 +214,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf } /// Returns the list of contacts pairs in this order: Local contact, other body contact -bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return false; } @@ -250,7 +250,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape); ERR_FAIL_COND_V(!shape, false); @@ -841,7 +841,7 @@ void SpaceBullet::check_body_collision() { Vector3 collisionWorldPosition; Vector3 collisionLocalPosition; Vector3 normalOnB; - float appliedImpulse = pt.m_appliedImpulse; + real_t appliedImpulse = pt.m_appliedImpulse; B_TO_G(pt.m_normalWorldOnB, normalOnB); // The pt.m_index only contains the shape index when more than one collision shape is used @@ -1062,7 +1062,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f return has_penetration; } -int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, float p_margin) { +int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) { btTransform body_transform; G_TO_B(p_transform, body_transform); UNSCALE_BT_BASIS(body_transform); diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 0f2482e551..1caa3c2a0c 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -78,11 +78,11 @@ public: virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, float p_margin, float &r_closest_safe, float &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; + virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; /// Returns the list of contacts pairs in this order: Local contact, other body contact - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, float p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, float p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override; }; @@ -189,7 +189,7 @@ public: real_t get_angular_damp() const { return angular_damp; } bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); - int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, float p_margin); + int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); private: void create_empty_world(bool p_create_soft_world); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 042c3aaca7..e348f8a568 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -927,25 +927,27 @@ CSGBrush *CSGSphere3D::_build_brush() { bool *invertw = invert.ptrw(); int face = 0; + const double lat_step = Math_TAU / rings; + const double lon_step = Math_TAU / radial_segments; for (int i = 1; i <= rings; i++) { - double lat0 = Math_PI * (-0.5 + (double)(i - 1) / rings); + double lat0 = lat_step * (i - 1) - Math_TAU / 4; double z0 = Math::sin(lat0); double zr0 = Math::cos(lat0); double u0 = double(i - 1) / rings; - double lat1 = Math_PI * (-0.5 + (double)i / rings); + double lat1 = lat_step * i - Math_TAU / 4; double z1 = Math::sin(lat1); double zr1 = Math::cos(lat1); double u1 = double(i) / rings; for (int j = radial_segments; j >= 1; j--) { - double lng0 = 2 * Math_PI * (double)(j - 1) / radial_segments; + double lng0 = lon_step * (j - 1); double x0 = Math::cos(lng0); double y0 = Math::sin(lng0); double v0 = double(i - 1) / radial_segments; - double lng1 = 2 * Math_PI * (double)(j) / radial_segments; + double lng1 = lon_step * j; double x1 = Math::cos(lng1); double y1 = Math::sin(lng1); double v1 = double(i) / radial_segments; @@ -1266,8 +1268,8 @@ CSGBrush *CSGCylinder3D::_build_brush() { float inc = float(i) / sides; float inc_n = float((i + 1)) / sides; - float ang = inc * Math_PI * 2.0; - float ang_n = inc_n * Math_PI * 2.0; + float ang = inc * Math_TAU; + float ang_n = inc_n * Math_TAU; Vector3 base(Math::cos(ang), 0, Math::sin(ang)); Vector3 base_n(Math::cos(ang_n), 0, Math::sin(ang_n)); @@ -1508,8 +1510,8 @@ CSGBrush *CSGTorus3D::_build_brush() { float inci = float(i) / sides; float inci_n = float((i + 1)) / sides; - float angi = inci * Math_PI * 2.0; - float angi_n = inci_n * Math_PI * 2.0; + float angi = inci * Math_TAU; + float angi_n = inci_n * Math_TAU; Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi)); Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n)); @@ -1518,8 +1520,8 @@ CSGBrush *CSGTorus3D::_build_brush() { float incj = float(j) / ring_sides; float incj_n = float((j + 1)) / ring_sides; - float angj = incj * Math_PI * 2.0; - float angj_n = incj_n * Math_PI * 2.0; + float angj = incj * Math_TAU; + float angj_n = incj_n * Math_TAU; Vector2 normalj = Vector2(Math::cos(angj), Math::sin(angj)) * radius + Vector2(min_radius + radius, 0); Vector2 normalj_n = Vector2(Math::cos(angj_n), Math::sin(angj_n)) * radius + Vector2(min_radius + radius, 0); @@ -1891,8 +1893,8 @@ CSGBrush *CSGPolygon3D::_build_brush() { float inci = float(i) / spin_sides; float inci_n = float((i + 1)) / spin_sides; - float angi = -(inci * spin_degrees / 360.0) * Math_PI * 2.0; - float angi_n = -(inci_n * spin_degrees / 360.0) * Math_PI * 2.0; + float angi = -Math::deg2rad(inci * spin_degrees); + float angi_n = -Math::deg2rad(inci_n * spin_degrees); Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi)); Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n)); diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 6661dbbb0b..43faa52218 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -267,12 +267,13 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann job_queue.num_tasks = static_cast<uint32_t>(tasks.size()); for (int i = 0; i < num_job_threads; i++) { - threads_wb[i] = Thread::create(_digest_job_queue, &job_queue); + threads_wb[i] = memnew(Thread); + threads_wb[i]->start(_digest_job_queue, &job_queue); } _digest_job_queue(&job_queue); for (int i = 0; i < num_job_threads; i++) { - Thread::wait_to_finish(threads_wb[i]); + threads_wb[i]->wait_to_finish(); memdelete(threads_wb[i]); } } diff --git a/modules/gdnative/android/android_gdn.cpp b/modules/gdnative/android/android_gdn.cpp index a48e51a390..fe3b3e7e12 100644 --- a/modules/gdnative/android/android_gdn.cpp +++ b/modules/gdnative/android/android_gdn.cpp @@ -48,7 +48,7 @@ extern "C" { JNIEnv *GDAPI godot_android_get_env() { #ifdef __ANDROID__ - return ThreadAndroid::get_env(); + return get_jni_env(); #else return nullptr; #endif diff --git a/modules/gdnative/include/gdnative/math_defs.h b/modules/gdnative/include/gdnative/math_defs.h index 05de157dd0..b5cf389506 100644 --- a/modules/gdnative/include/gdnative/math_defs.h +++ b/modules/gdnative/include/gdnative/math_defs.h @@ -35,6 +35,7 @@ extern "C" { #endif +#include <stdbool.h> #include <stdint.h> ////// bool diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index 6b46c9418a..2b824938f2 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -36,6 +36,7 @@ #include "core/core_constants.h" #include "core/object/class_db.h" #include "core/os/file_access.h" +#include "core/string/string_builder.h" #include "core/templates/pair.h" // helper stuff @@ -65,14 +66,14 @@ struct MethodAPI { Map<int, Variant> default_arguments; - int argument_count; - bool has_varargs; - bool is_editor; - bool is_noscript; - bool is_const; - bool is_reverse; - bool is_virtual; - bool is_from_script; + int argument_count = 0; + bool has_varargs = false; + bool is_editor = false; + bool is_noscript = false; + bool is_const = false; + bool is_reverse = false; + bool is_virtual = false; + bool is_from_script = false; }; struct PropertyAPI { @@ -80,12 +81,14 @@ struct PropertyAPI { String getter; String setter; String type; - int index; + int index = 0; }; struct ConstantAPI { String constant_name; - int constant_value; + int constant_value = 0; + Variant builtin_constant_value; // For builtin types; + String builtin_constant_type; // For builtin types; }; struct SignalAPI { @@ -100,23 +103,34 @@ struct EnumAPI { List<Pair<int, String>> values; }; +struct OperatorAPI { // For builtin types; + String name; + int oper = Variant::OP_MAX; + String other_type; + String return_type; +}; + struct ClassAPI { String class_name; String super_class_name; - ClassDB::APIType api_type; + ClassDB::APIType api_type = ClassDB::API_NONE; - bool is_singleton; + bool is_singleton = false; String singleton_name; - bool is_instanciable; + bool is_instantiable = false; // @Unclear - bool is_reference; + bool is_reference = false; + bool has_indexing = false; // For builtin types. + bool is_keyed = false; // For builtin types. List<MethodAPI> methods; + List<MethodAPI> constructors; // For builtin types. List<PropertyAPI> properties; List<ConstantAPI> constants; List<SignalAPI> signals_; List<EnumAPI> enums; + List<OperatorAPI> operators; // For builtin types. }; static String get_type_name(const PropertyInfo &info) { @@ -180,7 +194,7 @@ List<ClassAPI> generate_c_api_classes() { global_constants_api.api_type = ClassDB::API_CORE; global_constants_api.is_singleton = true; global_constants_api.singleton_name = "CoreConstants"; - global_constants_api.is_instanciable = false; + global_constants_api.is_instantiable = false; const int constants_count = CoreConstants::get_global_constant_count(); for (int i = 0; i < constants_count; ++i) { ConstantAPI constant_api; @@ -195,6 +209,10 @@ List<ClassAPI> generate_c_api_classes() { for (List<StringName>::Element *e = classes.front(); e != nullptr; e = e->next()) { StringName class_name = e->get(); + if (!ClassDB::is_class_exposed(class_name)) { + continue; + } + ClassAPI class_api; class_api.api_type = ClassDB::get_api_type(e->get()); class_api.class_name = class_name; @@ -209,7 +227,7 @@ List<ClassAPI> generate_c_api_classes() { class_api.singleton_name = name; } } - class_api.is_instanciable = !class_api.is_singleton && ClassDB::can_instance(class_name); + class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instance(class_name); { List<StringName> inheriters; @@ -402,6 +420,191 @@ List<ClassAPI> generate_c_api_classes() { } /* + * Reads the builtin Variant API to a list + */ +List<ClassAPI> generate_c_builtin_api_types() { + List<ClassAPI> api; + + // Special class for the utility methods. + { + ClassAPI utility_api; + utility_api.class_name = "Utilities"; + utility_api.is_instantiable = false; + + List<StringName> utility_functions; + Variant::get_utility_function_list(&utility_functions); + for (const List<StringName>::Element *E = utility_functions.front(); E; E = E->next()) { + const StringName &function_name = E->get(); + + MethodAPI function_api; + function_api.method_name = function_name; + function_api.has_varargs = Variant::is_utility_function_vararg(function_name); + function_api.argument_count = function_api.has_varargs ? 0 : Variant::get_utility_function_argument_count(function_name); + function_api.is_const = Variant::get_utility_function_type(function_name) == Variant::UTILITY_FUNC_TYPE_MATH; + + for (int i = 0; i < function_api.argument_count; i++) { + function_api.argument_names.push_back(Variant::get_utility_function_argument_name(function_name, i)); + Variant::Type arg_type = Variant::get_utility_function_argument_type(function_name, i); + function_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type)); + } + + if (Variant::has_utility_function_return_value(function_name)) { + Variant::Type ret_type = Variant::get_utility_function_return_type(function_name); + function_api.return_type = ret_type == Variant::NIL ? "Variant" : Variant::get_type_name(ret_type); + } else { + function_api.return_type = "void"; + } + + utility_api.methods.push_back(function_api); + } + + api.push_back(utility_api); + } + + for (int t = 0; t < Variant::VARIANT_MAX; t++) { + Variant::Type type = (Variant::Type)t; + + ClassAPI class_api; + class_api.class_name = Variant::get_type_name(type); + class_api.is_instantiable = true; + class_api.has_indexing = Variant::has_indexing(type); + class_api.is_keyed = Variant::is_keyed(type); + // Types that are passed by reference. + switch (type) { + case Variant::OBJECT: + case Variant::DICTIONARY: + case Variant::ARRAY: + case Variant::PACKED_BYTE_ARRAY: + case Variant::PACKED_INT32_ARRAY: + case Variant::PACKED_INT64_ARRAY: + case Variant::PACKED_FLOAT32_ARRAY: + case Variant::PACKED_FLOAT64_ARRAY: + case Variant::PACKED_STRING_ARRAY: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: + class_api.is_reference = true; + break; + default: + class_api.is_reference = false; + break; + } + + // Methods. + + List<StringName> methods; + Variant::get_builtin_method_list(type, &methods); + for (const List<StringName>::Element *E = methods.front(); E; E = E->next()) { + const StringName &method_name = E->get(); + + MethodAPI method_api; + + method_api.method_name = method_name; + method_api.argument_count = Variant::get_builtin_method_argument_count(type, method_name); + method_api.has_varargs = Variant::is_builtin_method_vararg(type, method_name); + method_api.is_const = Variant::is_builtin_method_const(type, method_name); + + for (int i = 0; i < method_api.argument_count; i++) { + method_api.argument_names.push_back(Variant::get_builtin_method_argument_name(type, method_name, i)); + Variant::Type arg_type = Variant::get_builtin_method_argument_type(type, method_name, i); + method_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type)); + } + + Vector<Variant> default_arguments = Variant::get_builtin_method_default_arguments(type, method_name); + + int default_start = method_api.argument_names.size() - default_arguments.size(); + + for (int i = 0; i < default_arguments.size(); i++) { + method_api.default_arguments[default_start + i] = default_arguments[i]; + } + + if (Variant::has_builtin_method_return_value(type, method_name)) { + Variant::Type ret_type = Variant::get_builtin_method_return_type(type, method_name); + method_api.return_type = ret_type == Variant::NIL ? "Variant" : Variant::get_type_name(ret_type); + } else { + method_api.return_type = "void"; + } + + class_api.methods.push_back(method_api); + } + + // Constructors. + + for (int c = 0; c < Variant::get_constructor_count(type); c++) { + MethodAPI constructor_api; + + constructor_api.method_name = Variant::get_type_name(type); + constructor_api.argument_count = Variant::get_constructor_argument_count(type, c); + constructor_api.return_type = Variant::get_type_name(type); + + for (int i = 0; i < constructor_api.argument_count; i++) { + constructor_api.argument_names.push_back(Variant::get_constructor_argument_name(type, c, i)); + Variant::Type arg_type = Variant::get_constructor_argument_type(type, c, i); + constructor_api.argument_types.push_back(arg_type == Variant::NIL ? "Variant" : Variant::get_type_name(arg_type)); + } + + class_api.constructors.push_back(constructor_api); + } + + // Constants. + + List<StringName> constants; + Variant::get_constants_for_type(type, &constants); + for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) { + const StringName &constant_name = E->get(); + ConstantAPI constant_api; + + constant_api.constant_name = constant_name; + constant_api.builtin_constant_value = Variant::get_constant_value(type, constant_name); + constant_api.builtin_constant_type = Variant::get_type_name(constant_api.builtin_constant_value.get_type()); + + class_api.constants.push_back(constant_api); + } + + // Members. + + List<StringName> members; + Variant::get_member_list(type, &members); + for (const List<StringName>::Element *E = members.front(); E; E = E->next()) { + const StringName &member_name = E->get(); + + PropertyAPI member_api; + member_api.name = member_name; + Variant::Type member_type = Variant::get_member_type(type, member_name); + member_api.type = member_type == Variant::NIL ? "Variant" : Variant::get_type_name(member_type); + + class_api.properties.push_back(member_api); + } + + // Operators. + + for (int op = 0; op < Variant::OP_MAX; op++) { + Variant::Operator oper = (Variant::Operator)op; + + for (int ot = 0; ot < Variant::VARIANT_MAX; ot++) { + Variant::Type other_type = (Variant::Type)ot; + + if (!Variant::get_validated_operator_evaluator(oper, type, other_type)) { + continue; + } + + OperatorAPI oper_api; + oper_api.name = Variant::get_operator_name(oper); + oper_api.oper = oper; + oper_api.other_type = Variant::get_type_name(other_type); + oper_api.return_type = Variant::get_type_name(Variant::get_operator_return_type(oper, type, other_type)); + + class_api.operators.push_back(oper_api); + } + } + + api.push_back(class_api); + } + + return api; +} + +/* * Generates the JSON source from the API in p_api */ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { @@ -421,9 +624,8 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back(String("\t\t\"api_type\": \"") + (api.api_type == ClassDB::API_CORE ? "core" : (api.api_type == ClassDB::API_EDITOR ? "tools" : "none")) + "\",\n"); source.push_back(String("\t\t\"singleton\": ") + (api.is_singleton ? "true" : "false") + ",\n"); source.push_back("\t\t\"singleton_name\": \"" + api.singleton_name + "\",\n"); - source.push_back(String("\t\t\"instanciable\": ") + (api.is_instanciable ? "true" : "false") + ",\n"); + source.push_back(String("\t\t\"instantiable\": ") + (api.is_instantiable ? "true" : "false") + ",\n"); source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n"); - // @Unclear source.push_back("\t\t\"constants\": {\n"); for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) { @@ -508,6 +710,164 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { return source; } +static int indent_level = 0; + +static void append_indented(StringBuilder &p_source, const String &p_text) { + for (int i = 0; i < indent_level; i++) { + p_source.append("\t"); + } + p_source.append(p_text); + p_source.append("\n"); +} + +static void append_indented(StringBuilder &p_source, const char *p_text) { + for (int i = 0; i < indent_level; i++) { + p_source.append("\t"); + } + p_source.append(p_text); + p_source.append("\n"); +} + +static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_method) { + append_indented(p_source, vformat(R"("name": "%s",)", p_method.method_name)); + append_indented(p_source, vformat(R"("return_type": "%s",)", p_method.return_type)); + append_indented(p_source, vformat(R"("is_const": %s,)", p_method.is_const ? "true" : "false")); + append_indented(p_source, vformat(R"("has_varargs": %s,)", p_method.has_varargs ? "true" : "false")); + + append_indented(p_source, R"("arguments": [)"); + indent_level++; + for (int i = 0; i < p_method.argument_count; i++) { + append_indented(p_source, "{"); + indent_level++; + + append_indented(p_source, vformat(R"("name": "%s",)", p_method.argument_names[i])); + append_indented(p_source, vformat(R"("type": "%s",)", p_method.argument_types[i])); + append_indented(p_source, vformat(R"("has_default_value": %s,)", p_method.default_arguments.has(i) ? "true" : "false")); + append_indented(p_source, vformat(R"("default_value": "%s")", p_method.default_arguments.has(i) ? p_method.default_arguments[i].operator String() : "")); + + indent_level--; + append_indented(p_source, i < p_method.argument_count - 1 ? "}," : "}"); + } + indent_level--; + append_indented(p_source, "]"); +} + +static List<String> generate_c_builtin_api_json(const List<ClassAPI> &p_api) { + StringBuilder source; + + source.append("[\n"); + + indent_level = 1; + + for (const List<ClassAPI>::Element *C = p_api.front(); C; C = C->next()) { + const ClassAPI &class_api = C->get(); + append_indented(source, "{"); + indent_level++; + + append_indented(source, vformat(R"("name": "%s",)", class_api.class_name)); + append_indented(source, vformat(R"("is_instantiable": %s,)", class_api.is_instantiable ? "true" : "false")); + append_indented(source, vformat(R"("is_reference": %s,)", class_api.is_reference ? "true" : "false")); + append_indented(source, vformat(R"("has_indexing": %s,)", class_api.has_indexing ? "true" : "false")); + append_indented(source, vformat(R"("is_keyed": %s,)", class_api.is_keyed ? "true" : "false")); + + // Constructors. + append_indented(source, R"("constructors": [)"); + indent_level++; + for (const List<MethodAPI>::Element *E = class_api.constructors.front(); E; E = E->next()) { + const MethodAPI &constructor = E->get(); + append_indented(source, "{"); + indent_level++; + + write_builtin_method(source, constructor); + + indent_level--; + append_indented(source, E->next() ? "}," : "}"); + } + indent_level--; + append_indented(source, "],"); + + // Constants. + append_indented(source, R"("constants": [)"); + indent_level++; + for (const List<ConstantAPI>::Element *E = class_api.constants.front(); E; E = E->next()) { + const ConstantAPI &constant = E->get(); + append_indented(source, "{"); + indent_level++; + + append_indented(source, vformat(R"("name": "%s",)", constant.constant_name)); + append_indented(source, vformat(R"("type": "%s",)", constant.builtin_constant_type)); + append_indented(source, vformat(R"("value": "%s")", constant.builtin_constant_value.operator String())); + + indent_level--; + append_indented(source, E->next() ? "}," : "}"); + } + indent_level--; + append_indented(source, "],"); + + // Methods. + append_indented(source, R"("methods": [)"); + indent_level++; + for (const List<MethodAPI>::Element *E = class_api.methods.front(); E; E = E->next()) { + const MethodAPI &method = E->get(); + append_indented(source, "{"); + indent_level++; + + write_builtin_method(source, method); + + indent_level--; + append_indented(source, E->next() ? "}," : "}"); + } + indent_level--; + append_indented(source, "],"); + + // Members. + append_indented(source, R"("members": [)"); + indent_level++; + for (const List<PropertyAPI>::Element *E = class_api.properties.front(); E; E = E->next()) { + const PropertyAPI &member = E->get(); + append_indented(source, "{"); + indent_level++; + + append_indented(source, vformat(R"("name": "%s",)", member.name)); + append_indented(source, vformat(R"("type": "%s")", member.type)); + + indent_level--; + append_indented(source, E->next() ? "}," : "}"); + } + indent_level--; + append_indented(source, "],"); + + // Operators. + append_indented(source, R"("operators": [)"); + indent_level++; + for (const List<OperatorAPI>::Element *E = class_api.operators.front(); E; E = E->next()) { + const OperatorAPI &oper = E->get(); + append_indented(source, "{"); + indent_level++; + + append_indented(source, vformat(R"("name": "%s",)", oper.name)); + append_indented(source, vformat(R"("operator": %d,)", oper.oper)); + append_indented(source, vformat(R"("other_type": "%s",)", oper.other_type)); + append_indented(source, vformat(R"("return_type": "%s")", oper.return_type)); + + indent_level--; + append_indented(source, E->next() ? "}," : "}"); + } + indent_level--; + append_indented(source, "]"); + + indent_level--; + append_indented(source, C->next() ? "}," : "}"); + } + + indent_level--; + source.append("]\n"); + + List<String> result; + result.push_back(source.as_string()); + return result; +} + #endif /* @@ -526,3 +886,19 @@ Error generate_c_api(const String &p_path) { return save_file(p_path, json_source); #endif } +/* + * Saves the builtin Godot API to a JSON file located at + * p_path + */ +Error generate_c_builtin_api(const String &p_path) { +#ifndef TOOLS_ENABLED + return ERR_BUG; +#else + + List<ClassAPI> api = generate_c_builtin_api_types(); + + List<String> json_source = generate_c_builtin_api_json(api); + + return save_file(p_path, json_source); +#endif +} diff --git a/modules/gdnative/nativescript/api_generator.h b/modules/gdnative/nativescript/api_generator.h index a324ded4a9..611abb2a2d 100644 --- a/modules/gdnative/nativescript/api_generator.h +++ b/modules/gdnative/nativescript/api_generator.h @@ -35,5 +35,6 @@ #include "core/typedefs.h" Error generate_c_api(const String &p_path); +Error generate_c_builtin_api(const String &p_path); #endif // API_GENERATOR_H diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 944f4f052c..19cf1f980b 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -1257,6 +1257,15 @@ void NativeScriptLanguage::init() { } exit(0); } + + E = args.find("--gdnative-generate-json-builtin-api"); + + if (E && E->next()) { + if (generate_c_builtin_api(E->next()->get()) != OK) { + ERR_PRINT("Failed to generate C builtin API\n"); + } + exit(0); + } #endif #ifdef TOOLS_ENABLED diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index aac9cb7fd7..12ed56a568 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -36,7 +36,6 @@ #include "editor/editor_node.h" GDScriptLanguageServer::GDScriptLanguageServer() { - thread = nullptr; thread_running = false; started = false; @@ -87,9 +86,8 @@ void GDScriptLanguageServer::start() { if (protocol.start(port, IP_Address("127.0.0.1")) == OK) { EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR); if (use_thread) { - ERR_FAIL_COND(thread != nullptr); thread_running = true; - thread = Thread::create(GDScriptLanguageServer::thread_main, this); + thread.start(GDScriptLanguageServer::thread_main, this); } set_process_internal(!use_thread); started = true; @@ -98,11 +96,9 @@ void GDScriptLanguageServer::start() { void GDScriptLanguageServer::stop() { if (use_thread) { - ERR_FAIL_COND(nullptr == thread); + ERR_FAIL_COND(!thread.is_started()); thread_running = false; - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); } protocol.stop(); started = false; diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h index 218f42199e..7b7837a463 100644 --- a/modules/gdscript/language_server/gdscript_language_server.h +++ b/modules/gdscript/language_server/gdscript_language_server.h @@ -40,7 +40,7 @@ class GDScriptLanguageServer : public EditorPlugin { GDScriptLanguageProtocol protocol; - Thread *thread; + Thread thread; bool thread_running; bool started; bool use_thread; diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 7b502f079b..69cad1a335 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -350,7 +350,7 @@ Error GDScriptWorkspace::parse_local_script(const String &p_path) { String GDScriptWorkspace::get_file_path(const String &p_uri) const { String path = p_uri; path = path.replace(root_uri + "/", "res://"); - path = path.http_unescape(); + path = path.uri_decode(); return path; } diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs index 16f91a0925..ed25cdaa63 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs @@ -104,7 +104,7 @@ namespace GodotTools.Ides.Rider if (line >= 0) { args.Add("--line"); - args.Add(line.ToString()); + args.Add((line + 1).ToString()); // https://github.com/JetBrains/godot-support/issues/61 } args.Add(scriptPath); try diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 90141928ca..0c333d06ef 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -104,7 +104,7 @@ namespace Godot /// <summary> /// The HSV hue of this color, on the range 0 to 1. /// </summary> - /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHsv"/>.</value> + /// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHSV"/>.</value> public float h { get @@ -145,14 +145,14 @@ namespace Godot } set { - this = FromHsv(value, s, v, a); + this = FromHSV(value, s, v, a); } } /// <summary> /// The HSV saturation of this color, on the range 0 to 1. /// </summary> - /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHsv"/>.</value> + /// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHSV"/>.</value> public float s { get @@ -166,14 +166,14 @@ namespace Godot } set { - this = FromHsv(h, value, v, a); + this = FromHSV(h, value, v, a); } } /// <summary> /// The HSV value (brightness) of this color, on the range 0 to 1. /// </summary> - /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHsv"/>.</value> + /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHSV"/>.</value> public float v { get @@ -182,7 +182,7 @@ namespace Godot } set { - this = FromHsv(h, s, value, a); + this = FromHSV(h, s, value, a); } } @@ -455,7 +455,7 @@ namespace Godot /// </summary> /// <param name="includeAlpha">Whether or not to include alpha. If false, the color is RGB instead of RGBA.</param> /// <returns>A string for the HTML hexadecimal representation of this color.</returns> - public string ToHtml(bool includeAlpha = true) + public string ToHTML(bool includeAlpha = true) { var txt = string.Empty; @@ -532,18 +532,50 @@ namespace Godot } /// <summary> + /// Constructs a color either from an HTML color code or from a + /// standardized color name. Supported + /// color names are the same as the <see cref="Colors"/> constants. + /// </summary> + /// <param name="code">The HTML color code or color name to construct from.</param> + public Color(string code) + { + if (HtmlIsValid(code)) + { + this = FromHTML(code); + } + else + { + this = Named(code); + } + } + + /// <summary> + /// Constructs a color either from an HTML color code or from a + /// standardized color name, with `alpha` on the range of 0 to 1. Supported + /// color names are the same as the <see cref="Colors"/> constants. + /// </summary> + /// <param name="code">The HTML color code or color name to construct from.</param> + /// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param> + public Color(string code, float alpha) + { + this = new Color(code); + a = alpha; + } + + /// <summary> /// Constructs a color from the HTML hexadecimal color string in RGBA format. /// </summary> /// <param name="rgba">A string for the HTML hexadecimal representation of this color.</param> - public Color(string rgba) + private static Color FromHTML(string rgba) { + Color c; if (rgba.Length == 0) { - r = 0f; - g = 0f; - b = 0f; - a = 1.0f; - return; + c.r = 0f; + c.g = 0f; + c.b = 0f; + c.a = 1.0f; + return c; } if (rgba[0] == '#') @@ -577,47 +609,48 @@ namespace Godot throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba); } - a = 1.0f; + c.a = 1.0f; if (isShorthand) { - r = ParseCol4(rgba, 0) / 15f; - g = ParseCol4(rgba, 1) / 15f; - b = ParseCol4(rgba, 2) / 15f; + c.r = ParseCol4(rgba, 0) / 15f; + c.g = ParseCol4(rgba, 1) / 15f; + c.b = ParseCol4(rgba, 2) / 15f; if (alpha) { - a = ParseCol4(rgba, 3) / 15f; + c.a = ParseCol4(rgba, 3) / 15f; } } else { - r = ParseCol8(rgba, 0) / 255f; - g = ParseCol8(rgba, 2) / 255f; - b = ParseCol8(rgba, 4) / 255f; + c.r = ParseCol8(rgba, 0) / 255f; + c.g = ParseCol8(rgba, 2) / 255f; + c.b = ParseCol8(rgba, 4) / 255f; if (alpha) { - a = ParseCol8(rgba, 6) / 255f; + c.a = ParseCol8(rgba, 6) / 255f; } } - if (r < 0) + if (c.r < 0) { throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba); } - if (g < 0) + if (c.g < 0) { throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba); } - if (b < 0) + if (c.b < 0) { throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba); } - if (a < 0) + if (c.a < 0) { throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba); } + return c; } /// <summary> @@ -640,9 +673,8 @@ namespace Godot /// the constants defined in <see cref="Colors"/>. /// </summary> /// <param name="name">The name of the color.</param> - /// <param name="alpha">The alpha (transparency) component represented on the range of 0 to 1. Default: 1.</param> /// <returns>The constructed color.</returns> - public static Color ColorN(string name, float alpha = 1f) + private static Color Named(string name) { name = name.Replace(" ", String.Empty); name = name.Replace("-", String.Empty); @@ -656,9 +688,7 @@ namespace Godot throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}"); } - Color color = Colors.namedColors[name]; - color.a = alpha; - return color; + return Colors.namedColors[name]; } /// <summary> @@ -671,11 +701,11 @@ namespace Godot /// <param name="value">The HSV value (brightness), typically on the range of 0 to 1.</param> /// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param> /// <returns>The constructed color.</returns> - public static Color FromHsv(float hue, float saturation, float value, float alpha = 1.0f) + public static Color FromHSV(float hue, float saturation, float value, float alpha = 1.0f) { if (saturation == 0) { - // acp_hromatic (grey) + // Achromatic (grey) return new Color(value, value, value, alpha); } @@ -715,7 +745,7 @@ namespace Godot /// <param name="hue">Output parameter for the HSV hue.</param> /// <param name="saturation">Output parameter for the HSV saturation.</param> /// <param name="value">Output parameter for the HSV value.</param> - public void ToHsv(out float hue, out float saturation, out float value) + public void ToHSV(out float hue, out float saturation, out float value) { float max = (float)Mathf.Max(r, Mathf.Max(g, b)); float min = (float)Mathf.Min(r, Mathf.Min(g, b)); @@ -803,7 +833,8 @@ namespace Godot } // Check if each hex digit is valid. - for (int i = 0; i < len; i++) { + for (int i = 0; i < len; i++) + { if (ParseCol4(color, i) == -1) { return false; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 0700f197ff..98efa89ef0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -97,6 +97,36 @@ namespace Godot return b; } + /// <summary> + /// Converts a string containing a binary number into an integer. + /// Binary strings can either be prefixed with `0b` or not, + /// and they can also start with a `-` before the optional prefix. + /// </summary> + /// <param name="instance">The string to convert.</param> + /// <returns>The converted string.</returns> + public static int BinToInt(this string instance) + { + if (instance.Length == 0) + { + return 0; + } + + int sign = 1; + + if (instance[0] == '-') + { + sign = -1; + instance = instance.Substring(1); + } + + if (instance.StartsWith("0b")) + { + instance = instance.Substring(2); + } + + return sign * Convert.ToInt32(instance, 2);; + } + // <summary> // Return the amount of substrings in string. // </summary> @@ -432,24 +462,24 @@ namespace Godot } // <summary> - // Hash the string and return a 32 bits integer. + // Hash the string and return a 32 bits unsigned integer. // </summary> - public static int Hash(this string instance) + public static uint Hash(this string instance) { - int index = 0; - int hashv = 5381; - int c; + uint hash = 5381; - while ((c = instance[index++]) != 0) - hashv = (hashv << 5) + hashv + c; // hash * 33 + c + foreach(uint c in instance) + { + hash = (hash << 5) + hash + c; // hash * 33 + c + } - return hashv; + return hash; } /// <summary> /// Returns a hexadecimal representation of this byte as a string. /// </summary> - /// <param name="bytes">The byte to encode.</param> + /// <param name="b">The byte to encode.</param> /// <returns>The hexadecimal representation of this byte.</returns> internal static string HexEncode(this byte b) { @@ -493,11 +523,20 @@ namespace Godot return ret; } - // <summary> - // Convert a string containing an hexadecimal number into an int. - // </summary> + /// <summary> + /// Converts a string containing a hexadecimal number into an integer. + /// Hexadecimal strings can either be prefixed with `0x` or not, + /// and they can also start with a `-` before the optional prefix. + /// </summary> + /// <param name="instance">The string to convert.</param> + /// <returns>The converted string.</returns> public static int HexToInt(this string instance) { + if (instance.Length == 0) + { + return 0; + } + int sign = 1; if (instance[0] == '-') @@ -506,10 +545,12 @@ namespace Godot instance = instance.Substring(1); } - if (!instance.StartsWith("0x")) - return 0; + if (instance.StartsWith("0x")) + { + instance = instance.Substring(2); + } - return sign * int.Parse(instance.Substring(2), NumberStyles.HexNumber); + return sign * int.Parse(instance, NumberStyles.HexNumber); } // <summary> @@ -892,22 +933,6 @@ namespace Godot } // <summary> - // Decode a percent-encoded string. See [method percent_encode]. - // </summary> - public static string PercentDecode(this string instance) - { - return Uri.UnescapeDataString(instance); - } - - // <summary> - // Percent-encode a string. This is meant to encode parameters in a URL when sending a HTTP GET request and bodies of form-urlencoded POST request. - // </summary> - public static string PercentEncode(this string instance) - { - return Uri.EscapeDataString(instance); - } - - // <summary> // If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code]. // </summary> public static string PlusFile(this string instance, string file) @@ -1169,6 +1194,33 @@ namespace Godot return Encoding.UTF8.GetBytes(instance); } + /// <summary> + /// Decodes a string in URL encoded format. This is meant to + /// decode parameters in a URL when receiving an HTTP request. + /// This mostly wraps around `System.Uri.UnescapeDataString()`, + /// but also handles `+`. + /// See <see cref="URIEncode"/> for encoding. + /// </summary> + /// <param name="instance">The string to decode.</param> + /// <returns>The unescaped string.</returns> + public static string URIDecode(this string instance) + { + return Uri.UnescapeDataString(instance.Replace("+", "%20")); + } + + /// <summary> + /// Encodes a string to URL friendly format. This is meant to + /// encode parameters in a URL when sending an HTTP request. + /// This wraps around `System.Uri.EscapeDataString()`. + /// See <see cref="URIDecode"/> for decoding. + /// </summary> + /// <param name="instance">The string to encode.</param> + /// <returns>The escaped string.</returns> + public static string URIEncode(this string instance) + { + return Uri.EscapeDataString(instance); + } + // <summary> // Return a copy of the string with special characters escaped using the XML standard. // </summary> diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp index 59e1385e7e..cba29d63cd 100644 --- a/modules/mono/mono_gd/support/android_support.cpp +++ b/modules/mono/mono_gd/support/android_support.cpp @@ -109,7 +109,7 @@ bool jni_exception_check(JNIEnv *p_env) { String app_native_lib_dir_cache; String determine_app_native_lib_dir() { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jclass> activityThreadClass(env, env->FindClass("android/app/ActivityThread")); jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;"); @@ -253,7 +253,7 @@ int32_t get_build_version_sdk_int() { // android.os.Build.VERSION.SDK_INT if (build_version_sdk_int == 0) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass versionClass = env->FindClass("android/os/Build$VERSION"); ERR_FAIL_NULL_V(versionClass, 0); @@ -281,7 +281,7 @@ MonoBoolean _gd_mono_init_cert_store() { // return false; // } - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore")); @@ -322,7 +322,7 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { return nullptr; } - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jstring> js_alias(env, env->NewStringUTF(alias_utf8)); mono_free(alias_utf8); @@ -380,7 +380,7 @@ void cleanup() { if (godot_dl_handle) gd_mono_android_dlclose(godot_dl_handle, nullptr); - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); if (certStore) { env->DeleteGlobalRef(certStore); @@ -437,7 +437,7 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char *r_is_up = 0; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface"); ERR_FAIL_NULL_V(networkInterfaceClass, 0); @@ -469,7 +469,7 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast( *r_supports_multicast = 0; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface"); ERR_FAIL_NULL_V(networkInterfaceClass, 0); @@ -507,7 +507,7 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn CRASH_COND(get_build_version_sdk_int() < 23); #endif - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); GodotJavaWrapper *godot_java = ((OS_Android *)OS::get_singleton())->get_godot_java(); jobject activity = godot_java->get_activity(); @@ -648,7 +648,7 @@ GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() { // // TimeZone.getDefault().getID() - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jclass> timeZoneClass(env, env->FindClass("java/util/TimeZone")); ERR_FAIL_NULL_V(timeZoneClass, nullptr); diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index 1d75e46747..30a0ca3464 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -34,7 +34,6 @@ NoiseTexture::NoiseTexture() { update_queued = false; - noise_thread = nullptr; regen_queued = false; first_time = true; @@ -52,10 +51,7 @@ NoiseTexture::~NoiseTexture() { if (texture.is_valid()) { RS::get_singleton()->free(texture); } - if (noise_thread) { - Thread::wait_to_finish(noise_thread); - memdelete(noise_thread); - } + noise_thread.wait_to_finish(); } void NoiseTexture::_bind_methods() { @@ -109,11 +105,9 @@ void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) { void NoiseTexture::_thread_done(const Ref<Image> &p_image) { _set_texture_data(p_image); - Thread::wait_to_finish(noise_thread); - memdelete(noise_thread); - noise_thread = nullptr; + noise_thread.wait_to_finish(); if (regen_queued) { - noise_thread = Thread::create(_thread_function, this); + noise_thread.start(_thread_function, this); regen_queued = false; } } @@ -165,8 +159,8 @@ void NoiseTexture::_update_texture() { use_thread = false; #endif if (use_thread) { - if (!noise_thread) { - noise_thread = Thread::create(_thread_function, this); + if (!noise_thread.is_started()) { + noise_thread.start(_thread_function, this); regen_queued = false; } else { regen_queued = true; diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h index 9f6e2cbf43..170275bd2e 100644 --- a/modules/opensimplex/noise_texture.h +++ b/modules/opensimplex/noise_texture.h @@ -45,7 +45,7 @@ class NoiseTexture : public Texture2D { private: Ref<Image> data; - Thread *noise_thread; + Thread noise_thread; bool first_time; bool update_queued; diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp index e4e2e0613a..a823bcf3b8 100644 --- a/modules/opensimplex/open_simplex_noise.cpp +++ b/modules/opensimplex/open_simplex_noise.cpp @@ -131,10 +131,10 @@ Ref<Image> OpenSimplexNoise::get_seamless_image(int p_size) const { float ii = (float)i / (float)p_size; float jj = (float)j / (float)p_size; - ii *= 2.0 * Math_PI; - jj *= 2.0 * Math_PI; + ii *= Math_TAU; + jj *= Math_TAU; - float radius = p_size / (2.0 * Math_PI); + float radius = p_size / Math_TAU; float x = radius * Math::sin(jj); float y = radius * Math::cos(jj); diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp index 01fa94aa7c..51cc242348 100644 --- a/modules/text_server_adv/bitmap_font_adv.cpp +++ b/modules/text_server_adv/bitmap_font_adv.cpp @@ -540,7 +540,7 @@ Vector2 BitmapFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vecto ERR_FAIL_COND_V(c == nullptr, Vector2()); ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2()); if (c->texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += c->align * (float(p_size) / float(base_size)); cpos.y -= ascent * (float(p_size) / float(base_size)); if (RenderingServer::get_singleton() != nullptr) { diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp index fcefa60d98..5a16158c0f 100644 --- a/modules/text_server_adv/dynamic_font_adv.cpp +++ b/modules/text_server_adv/dynamic_font_adv.cpp @@ -946,7 +946,7 @@ Vector2 DynamicFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vect ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; if (FT_HAS_COLOR(fds->face)) { @@ -977,7 +977,7 @@ Vector2 DynamicFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, in ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; if (FT_HAS_COLOR(fds->face)) { diff --git a/modules/text_server_fb/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp index 5c691b7bbd..6bc838bd6a 100644 --- a/modules/text_server_fb/bitmap_font_fb.cpp +++ b/modules/text_server_fb/bitmap_font_fb.cpp @@ -321,7 +321,7 @@ Vector2 BitmapFontDataFallback::draw_glyph(RID p_canvas, int p_size, const Vecto ERR_FAIL_COND_V(c == nullptr, Vector2()); ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2()); if (c->texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += c->align * (float(p_size) / float(base_size)); cpos.y -= ascent * (float(p_size) / float(base_size)); diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp index 4eecba6ae8..df7756cbd0 100644 --- a/modules/text_server_fb/dynamic_font_fb.cpp +++ b/modules/text_server_fb/dynamic_font_fb.cpp @@ -626,7 +626,7 @@ Vector2 DynamicFontDataFallback::draw_glyph(RID p_canvas, int p_size, const Vect ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; @@ -658,7 +658,7 @@ Vector2 DynamicFontDataFallback::draw_glyph_outline(RID p_canvas, int p_size, in ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 243265769e..1026d58b85 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -140,9 +140,7 @@ void VideoStreamPlaybackTheora::clear() { #ifdef THEORA_USE_THREAD_STREAMING thread_exit = true; thread_sem->post(); //just in case - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); ring_buffer.clear(); #endif @@ -181,7 +179,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { int read = file->get_buffer(read_buffer.ptr(), to_read); ring_buffer.write(read_buffer.ptr(), read); - thread = Thread::create(_streaming_thread, this); + thread.start(_streaming_thread, this); #endif @@ -669,7 +667,6 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() { ring_buffer.resize(rb_power); read_buffer.resize(RB_SIZE_KB * 1024); thread_sem = Semaphore::create(); - thread = nullptr; thread_exit = false; thread_eof = false; diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index d2036b5cb4..c315d682da 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -112,7 +112,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { Vector<uint8_t> read_buffer; bool thread_eof; Semaphore *thread_sem; - Thread *thread; + Thread thread; volatile bool thread_exit; static void _streaming_thread(void *ud); diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml index 4004f1a04c..219ffd01d3 100644 --- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml +++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml @@ -202,24 +202,20 @@ <constant name="BYTES_TO_VAR" value="62" enum="BuiltinFunc"> Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES]. </constant> - <constant name="COLORN" value="63" enum="BuiltinFunc"> - Return the [Color] with the given name and alpha ranging from 0 to 1. - [b]Note:[/b] Names are defined in [code]color_names.inc[/code]. - </constant> - <constant name="MATH_SMOOTHSTEP" value="64" enum="BuiltinFunc"> + <constant name="MATH_SMOOTHSTEP" value="63" enum="BuiltinFunc"> Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula: [codeblock] var t = clamp((weight - from) / (to - from), 0.0, 1.0) return t * t * (3.0 - 2.0 * t) [/codeblock] </constant> - <constant name="MATH_POSMOD" value="65" enum="BuiltinFunc"> + <constant name="MATH_POSMOD" value="64" enum="BuiltinFunc"> </constant> - <constant name="MATH_LERP_ANGLE" value="66" enum="BuiltinFunc"> + <constant name="MATH_LERP_ANGLE" value="65" enum="BuiltinFunc"> </constant> - <constant name="TEXT_ORD" value="67" enum="BuiltinFunc"> + <constant name="TEXT_ORD" value="66" enum="BuiltinFunc"> </constant> - <constant name="FUNC_MAX" value="68" enum="BuiltinFunc"> + <constant name="FUNC_MAX" value="67" enum="BuiltinFunc"> Represents the size of the [enum BuiltinFunc] enum. </constant> </constants> diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 2558c1d7ec..b96311ba6c 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -101,7 +101,6 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "str2var", "var2bytes", "bytes2var", - "color_named", "smoothstep", "posmod", "lerp_angle", @@ -200,7 +199,6 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case LOGIC_MAX: case LOGIC_MIN: case TYPE_CONVERT: - case COLORN: return 2; case MATH_LERP: case MATH_LERP_ANGLE: @@ -476,13 +474,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::BOOL, "allow_objects"); } } break; - case COLORN: { - if (p_idx == 0) { - return PropertyInfo(Variant::STRING, "name"); - } else { - return PropertyInfo(Variant::FLOAT, "alpha"); - } - } break; case FUNC_MAX: { } } @@ -635,9 +626,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons t = Variant::BOOL; } } break; - case COLORN: { - t = Variant::COLOR; - } break; case FUNC_MAX: { } } @@ -1176,15 +1164,6 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in *r_return = ret; } break; - case VisualScriptBuiltinFunc::COLORN: { - VALIDATE_ARG_NUM(1); - - Color color = Color::named(*p_inputs[0]); - color.a = *p_inputs[1]; - - *r_return = String(color); - - } break; default: { } } @@ -1292,7 +1271,6 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(STR_TO_VAR); BIND_ENUM_CONSTANT(VAR_TO_BYTES); BIND_ENUM_CONSTANT(BYTES_TO_VAR); - BIND_ENUM_CONSTANT(COLORN); BIND_ENUM_CONSTANT(MATH_SMOOTHSTEP); BIND_ENUM_CONSTANT(MATH_POSMOD); BIND_ENUM_CONSTANT(MATH_LERP_ANGLE); @@ -1388,5 +1366,4 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var", create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var", create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/color_named", create_builtin_func_node<VisualScriptBuiltinFunc::COLORN>); } diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index eaa2ef41e2..1fafaf1d98 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -101,7 +101,6 @@ public: STR_TO_VAR, VAR_TO_BYTES, BYTES_TO_VAR, - COLORN, MATH_SMOOTHSTEP, MATH_POSMOD, MATH_LERP_ANGLE, diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml index bddffd910e..2407d44496 100644 --- a/modules/webxr/doc_classes/WebXRInterface.xml +++ b/modules/webxr/doc_classes/WebXRInterface.xml @@ -10,75 +10,79 @@ Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to intialize than other AR/VR interfaces. Here's the minimum code required to start an immersive VR session: [codeblock] - var webxr_interface - var vr_supported = false + extends Node3D - func _ready(): - # We assume this node has a canvas layer with a button on it as a child. - # This button is for the user to consent to entering immersive VR mode. - $CanvasLayer/Button.connect("pressed", self, "_on_Button_pressed") + var webxr_interface + var vr_supported = false - webxr_interface = XRServer.find_interface("WebXR") - if webxr_interface: - # WebXR uses a lot of asynchronous callbacks, so we connect to various - # signals in order to receive them. - webxr_interface.connect("session_supported", self, "_webxr_session_supported") - webxr_interface.connect("session_started", self, "_webxr_session_started") - webxr_interface.connect("session_ended", self, "_webxr_session_ended") - webxr_interface.connect("session_failed", self, "_webxr_session_failed") + func _ready(): + # We assume this node has a button as a child. + # This button is for the user to consent to entering immersive VR mode. + $Button.connect("pressed", self, "_on_Button_pressed") - # This returns immediately - our _webxr_session_supported() method - # (which we connected to the "session_supported" signal above) will - # be called sometime later to let us know if it's supported or not. - webxr_interface.is_session_supported("immersive-vr") + webxr_interface = XRServer.find_interface("WebXR") + if webxr_interface: + # WebXR uses a lot of asynchronous callbacks, so we connect to various + # signals in order to receive them. + webxr_interface.connect("session_supported", self, "_webxr_session_supported") + webxr_interface.connect("session_started", self, "_webxr_session_started") + webxr_interface.connect("session_ended", self, "_webxr_session_ended") + webxr_interface.connect("session_failed", self, "_webxr_session_failed") - func _webxr_session_supported(session_mode, supported): - if session_mode == 'immersive-vr': - vr_supported = supported + # This returns immediately - our _webxr_session_supported() method + # (which we connected to the "session_supported" signal above) will + # be called sometime later to let us know if it's supported or not. + webxr_interface.is_session_supported("immersive-vr") - func _on_Button_pressed(): - if not vr_supported: - OS.alert("Your browser doesn't support VR") - return + func _webxr_session_supported(session_mode, supported): + if session_mode == 'immersive-vr': + vr_supported = supported - # We want an immersive VR session, as opposed to AR ('immersive-ar') or a - # simple 3DoF viewer ('viewer'). - webxr_interface.session_mode = 'immersive-vr' - # 'bounded-floor' is room scale, 'local-floor' is a standing or sitting - # experience (it puts you 1.6m above the ground if you have 3DoF headset), - # whereas as 'local' puts you down at the XROrigin. - # This list means it'll first try to request 'bounded-floor', then - # fallback on 'local-floor' and ultimately 'local', if nothing else is - # supported. - webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local' - # In order to use 'local-floor' or 'bounded-floor' we must also - # mark the features as required or optional. - webxr_interface.required_features = 'local-floor' - webxr_interface.optional_features = 'bounded-floor' + func _on_Button_pressed(): + if not vr_supported: + OS.alert("Your browser doesn't support VR") + return - # This will return false if we're unable to even request the session, - # however, it can still fail asynchronously later in the process, so we - # only know if it's really succeeded or failed when our - # _webxr_session_started() or _webxr_session_failed() methods are called. - if not webxr_interface.initialize(): - OS.alert("Failed to initialize") - return + # We want an immersive VR session, as opposed to AR ('immersive-ar') or a + # simple 3DoF viewer ('viewer'). + webxr_interface.session_mode = 'immersive-vr' + # 'bounded-floor' is room scale, 'local-floor' is a standing or sitting + # experience (it puts you 1.6m above the ground if you have 3DoF headset), + # whereas as 'local' puts you down at the XROrigin. + # This list means it'll first try to request 'bounded-floor', then + # fallback on 'local-floor' and ultimately 'local', if nothing else is + # supported. + webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local' + # In order to use 'local-floor' or 'bounded-floor' we must also + # mark the features as required or optional. + webxr_interface.required_features = 'local-floor' + webxr_interface.optional_features = 'bounded-floor' - func _webxr_session_started(): - # This tells Godot to start rendering to the headset. - get_viewport().xr = true - # This will be the reference space type you ultimately got, out of the - # types that you requested above. This is useful if you want the game to - # work a little differently in 'bounded-floor' versus 'local-floor'. - print ("Reference space type: " + webxr_interface.reference_space_type) + # This will return false if we're unable to even request the session, + # however, it can still fail asynchronously later in the process, so we + # only know if it's really succeeded or failed when our + # _webxr_session_started() or _webxr_session_failed() methods are called. + if not webxr_interface.initialize(): + OS.alert("Failed to initialize") + return - func _webxr_session_ended(): - # If the user exits immersive mode, then we tell Godot to render to the web - # page again. - get_viewport().xr = false + func _webxr_session_started(): + $Button.visible = false + # This tells Godot to start rendering to the headset. + get_viewport().xr = true + # This will be the reference space type you ultimately got, out of the + # types that you requested above. This is useful if you want the game to + # work a little differently in 'bounded-floor' versus 'local-floor'. + print ("Reference space type: " + webxr_interface.reference_space_type) - func _webxr_session_failed(message): - OS.alert("Failed to initialize: " + message) + func _webxr_session_ended(): + $Button.visible = true + # If the user exits immersive mode, then we tell Godot to render to the web + # page again. + get_viewport().xr = false + + func _webxr_session_failed(message): + OS.alert("Failed to initialize: " + message) [/codeblock] There are several ways to handle "controller" input: - Using [XRController3D] nodes and their [signal XRController3D.button_pressed] and [signal XRController3D.button_released] signals. This is how controllers are typically handled in AR/VR apps in Godot, however, this will only work with advanced VR controllers like the Oculus Touch or Index controllers, for example. The buttons codes are defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url]. diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h index 5e50ffde28..41a690f473 100644 --- a/modules/webxr/godot_webxr.h +++ b/modules/webxr/godot_webxr.h @@ -61,6 +61,7 @@ extern void godot_webxr_initialize( GodotWebXRSimpleEventCallback p_on_simple_event); extern void godot_webxr_uninitialize(); +extern int godot_webxr_get_view_count(); extern int *godot_webxr_get_render_targetsize(); extern float *godot_webxr_get_transform_for_eye(int p_eye); extern float *godot_webxr_get_projection_for_eye(int p_eye); diff --git a/modules/webxr/native/library_godot_webxr.js b/modules/webxr/native/library_godot_webxr.js index 3041c16c79..8e9ef8a73c 100644 --- a/modules/webxr/native/library_godot_webxr.js +++ b/modules/webxr/native/library_godot_webxr.js @@ -380,6 +380,11 @@ const GodotWebXR = { gl.deleteTexture(texture); } GodotWebXR.textures[i] = null; + + const texture_id = GodotWebXR.texture_ids[i]; + if (texture_id !== null) { + GL.textures[texture_id] = null; + } GodotWebXR.texture_ids[i] = null; } @@ -394,6 +399,15 @@ const GodotWebXR = { GodotWebXR.pauseResumeMainLoop(); }, + godot_webxr_get_view_count__proxy: 'sync', + godot_webxr_get_view_count__sig: 'i', + godot_webxr_get_view_count: function () { + if (!GodotWebXR.session || !GodotWebXR.pose) { + return 0; + } + return GodotWebXR.pose.views.length; + }, + godot_webxr_get_render_targetsize__proxy: 'sync', godot_webxr_get_render_targetsize__sig: 'i', godot_webxr_get_render_targetsize: function () { @@ -451,7 +465,7 @@ const GodotWebXR = { godot_webxr_get_external_texture_for_eye__proxy: 'sync', godot_webxr_get_external_texture_for_eye__sig: 'ii', godot_webxr_get_external_texture_for_eye: function (p_eye) { - if (!GodotWebXR.session || !GodotWebXR.pose) { + if (!GodotWebXR.session) { return 0; } @@ -460,6 +474,13 @@ const GodotWebXR = { return GodotWebXR.texture_ids[view_index]; } + // Check pose separately and after returning the cached texture id, + // because we won't get a pose in some cases if we lose tracking, and + // we don't want to return 0 just because tracking was lost. + if (!GodotWebXR.pose) { + return 0; + } + const glLayer = GodotWebXR.session.renderState.baseLayer; const view = GodotWebXR.pose.views[view_index]; const viewport = glLayer.getViewport(view); diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 6594553146..74789fc98e 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -78,6 +78,8 @@ void _emwebxr_on_session_failed(char *p_message) { Ref<XRInterface> interface = xr_server->find_interface("WebXR"); ERR_FAIL_COND(interface.is_null()); + interface->uninitialize(); + String message = String(p_message); interface->emit_signal("session_failed", message); } @@ -197,12 +199,11 @@ StringName WebXRInterfaceJS::get_name() const { }; int WebXRInterfaceJS::get_capabilities() const { - return XRInterface::XR_STEREO; + return XRInterface::XR_STEREO | XRInterface::XR_MONO; }; bool WebXRInterfaceJS::is_stereo() { - // @todo WebXR can be mono! So, how do we know? Count the views in the frame? - return true; + return godot_webxr_get_view_count() == 2; }; bool WebXRInterfaceJS::is_initialized() const { @@ -225,6 +226,12 @@ bool WebXRInterfaceJS::initialize() { // make this our primary interface xr_server->set_primary_interface(this); + // Clear render_targetsize to make sure it gets reset to the new size. + // Clearing in uninitialize() doesn't work because a frame can still be + // rendered after it's called, which will fill render_targetsize again. + render_targetsize.width = 0; + render_targetsize.height = 0; + initialized = true; godot_webxr_initialize( @@ -278,22 +285,24 @@ Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { } Size2 WebXRInterfaceJS::get_render_targetsize() { - Size2 target_size; + if (render_targetsize.width != 0 && render_targetsize.height != 0) { + return render_targetsize; + } int *js_size = godot_webxr_get_render_targetsize(); if (!initialized || js_size == nullptr) { - // As a default, use half the window size. - target_size = DisplayServer::get_singleton()->window_get_size(); - target_size.width /= 2.0; - return target_size; + // As a temporary default (until WebXR is fully initialized), use half the window size. + Size2 temp = DisplayServer::get_singleton()->window_get_size(); + temp.width /= 2.0; + return temp; } - target_size.width = js_size[0]; - target_size.height = js_size[1]; + render_targetsize.width = js_size[0]; + render_targetsize.height = js_size[1]; free(js_size); - return target_size; + return render_targetsize; }; Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h index 93da9a6d12..49299b252f 100644 --- a/modules/webxr/webxr_interface_js.h +++ b/modules/webxr/webxr_interface_js.h @@ -47,7 +47,6 @@ class WebXRInterfaceJS : public WebXRInterface { private: bool initialized; - // @todo Should these really use enums instead of strings? String session_mode; String required_features; String optional_features; @@ -55,6 +54,7 @@ private: String reference_space_type; bool controllers_state[2]; + Size2 render_targetsize; Transform _js_matrix_to_transform(float *p_js_matrix); void _update_tracker(int p_controller_id); |