diff options
Diffstat (limited to 'servers')
29 files changed, 284 insertions, 136 deletions
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp index 88f2040d17..e5678914fe 100644 --- a/servers/physics_3d/gjk_epa.cpp +++ b/servers/physics_3d/gjk_epa.cpp @@ -1011,9 +1011,11 @@ bool gjk_epa_calculate_penetration(const GodotShape3D *p_shape_A, const Transfor if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) { if (p_result_callback) { if (p_swap) { - p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, p_userdata); + Vector3 normal = (res.witnesses[1] - res.witnesses[0]).normalized(); + p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, normal, p_userdata); } else { - p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, p_userdata); + Vector3 normal = (res.witnesses[0] - res.witnesses[1]).normalized(); + p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, normal, p_userdata); } } return true; diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/servers/physics_3d/godot_body_pair_3d.cpp index ce3da390cb..619e6c00be 100644 --- a/servers/physics_3d/godot_body_pair_3d.cpp +++ b/servers/physics_3d/godot_body_pair_3d.cpp @@ -38,12 +38,12 @@ #define MIN_VELOCITY 0.0001 #define MAX_BIAS_ROTATION (Math_PI / 8) -void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { GodotBodyPair3D *pair = static_cast<GodotBodyPair3D *>(p_userdata); - pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B); + pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal); } -void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { +void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) { Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A); Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B); @@ -577,12 +577,12 @@ GodotBodyPair3D::~GodotBodyPair3D() { B->remove_constraint(this); } -void GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { GodotBodySoftBodyPair3D *pair = static_cast<GodotBodySoftBodyPair3D *>(p_userdata); - pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B); + pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal); } -void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { +void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) { Vector3 local_A = body->get_inv_transform().xform(p_point_A); Vector3 local_B = p_point_B - soft_body->get_node_position(p_index_B); @@ -591,7 +591,7 @@ void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, i contact.index_B = p_index_B; contact.local_A = local_A; contact.local_B = local_B; - contact.normal = (p_point_A - p_point_B).normalized(); + contact.normal = (normal.dot((p_point_A - p_point_B)) < 0 ? -normal : normal); contact.used = true; // Attempt to determine if the contact will be reused. diff --git a/servers/physics_3d/godot_body_pair_3d.h b/servers/physics_3d/godot_body_pair_3d.h index c3165c7fcf..a8f5180dd5 100644 --- a/servers/physics_3d/godot_body_pair_3d.h +++ b/servers/physics_3d/godot_body_pair_3d.h @@ -97,9 +97,9 @@ class GodotBodyPair3D : public GodotBodyContact3D { Contact contacts[MAX_CONTACTS]; int contact_count = 0; - static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); - void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B); + void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal); void validate_contacts(); bool _test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A, const Transform3D &p_xform_A, GodotBody3D *p_B, int p_shape_B, const Transform3D &p_xform_B); @@ -126,9 +126,9 @@ class GodotBodySoftBodyPair3D : public GodotBodyContact3D { LocalVector<Contact> contacts; - static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); - void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B); + void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal); void validate_contacts(); diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp index 0b92b745fe..fb5a67c008 100644 --- a/servers/physics_3d/godot_collision_solver_3d.cpp +++ b/servers/physics_3d/godot_collision_solver_3d.cpp @@ -81,9 +81,11 @@ bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_s if (p_result_callback) { if (p_swap_result) { - p_result_callback(supports[i], 0, support_A, 0, p_userdata); + Vector3 normal = (support_A - supports[i]).normalized(); + p_result_callback(supports[i], 0, support_A, 0, normal, p_userdata); } else { - p_result_callback(support_A, 0, supports[i], 0, p_userdata); + Vector3 normal = (supports[i] - support_A).normalized(); + p_result_callback(support_A, 0, supports[i], 0, normal, p_userdata); } } } @@ -126,9 +128,11 @@ bool GodotCollisionSolver3D::solve_separation_ray(const GodotShape3D *p_shape_A, if (p_result_callback) { if (p_swap_result) { - p_result_callback(support_B, 0, support_A, 0, p_userdata); + Vector3 normal = (support_B - support_A).normalized(); + p_result_callback(support_B, 0, support_A, 0, normal, p_userdata); } else { - p_result_callback(support_A, 0, support_B, 0, p_userdata); + Vector3 normal = (support_A - support_B).normalized(); + p_result_callback(support_A, 0, support_B, 0, normal, p_userdata); } } return true; @@ -142,7 +146,7 @@ struct _SoftBodyContactCollisionInfo { int contact_count = 0; }; -void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { _SoftBodyContactCollisionInfo &cinfo = *(static_cast<_SoftBodyContactCollisionInfo *>(p_userdata)); ++cinfo.contact_count; @@ -152,9 +156,9 @@ void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A } if (cinfo.swap_result) { - cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata); + cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, -normal, cinfo.userdata); } else { - cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, cinfo.userdata); + cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, normal, cinfo.userdata); } } diff --git a/servers/physics_3d/godot_collision_solver_3d.h b/servers/physics_3d/godot_collision_solver_3d.h index 7ef0dc97ac..36ea79576e 100644 --- a/servers/physics_3d/godot_collision_solver_3d.h +++ b/servers/physics_3d/godot_collision_solver_3d.h @@ -35,11 +35,11 @@ class GodotCollisionSolver3D { public: - typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); private: static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata); - static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); static bool soft_body_concave_callback(void *p_userdata, GodotShape3D *p_convex); static bool concave_callback(void *p_userdata, GodotShape3D *p_convex); static bool solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0); diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp index d13f4ee801..2cb29b3dd0 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp +++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp @@ -75,11 +75,13 @@ struct _CollectorCallback { Vector3 normal; Vector3 *prev_axis = nullptr; - _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) { + _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B, Vector3 p_normal) { + if (p_normal.dot(p_point_B - p_point_A) < 0) + p_normal = -p_normal; if (swap) { - callback(p_point_B, 0, p_point_A, 0, userdata); + callback(p_point_B, 0, p_point_A, 0, -p_normal, userdata); } else { - callback(p_point_A, 0, p_point_B, 0, userdata); + callback(p_point_A, 0, p_point_B, 0, p_normal, userdata); } } }; @@ -92,7 +94,7 @@ static void _generate_contacts_point_point(const Vector3 *p_points_A, int p_poin ERR_FAIL_COND(p_point_count_B != 1); #endif - p_callback->call(*p_points_A, *p_points_B); + p_callback->call(*p_points_A, *p_points_B, p_callback->normal); } static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -102,7 +104,7 @@ static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point #endif Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B); - p_callback->call(*p_points_A, closest_B); + p_callback->call(*p_points_A, closest_B, p_callback->normal); } static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -111,9 +113,9 @@ static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point ERR_FAIL_COND(p_point_count_B < 3); #endif - Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A); - - p_callback->call(*p_points_A, closest_B); + Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]); + Vector3 closest_B = plane.project(*p_points_A); + p_callback->call(*p_points_A, closest_B, plane.get_normal()); } static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -122,9 +124,9 @@ static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_poi ERR_FAIL_COND(p_point_count_B != 3); #endif - Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A); - - p_callback->call(*p_points_A, closest_B); + Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]); + Vector3 closest_B = plane.project(*p_points_A); + p_callback->call(*p_points_A, closest_B, plane.get_normal()); } static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -154,8 +156,8 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_ sa.sort(dvec, 4); //use the middle ones as contacts - p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1]); - p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2]); + p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1], p_callback->normal); + p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2], p_callback->normal); return; } @@ -170,7 +172,14 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_ Vector3 closest_A = p_points_A[0] + rel_A * d; Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(closest_A, p_points_B); - p_callback->call(closest_A, closest_B); + // The normal should be perpendicular to both edges. + Vector3 normal = rel_A.cross(rel_B); + real_t normal_len = normal.length(); + if (normal_len > 1e-3) + normal /= normal_len; + else + normal = p_callback->normal; + p_callback->call(closest_A, closest_B, normal); } static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) { @@ -267,7 +276,7 @@ static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_poin continue; } - p_callback->call(contact_point_A, closest_B); + p_callback->call(contact_point_A, closest_B, circle_plane.get_normal()); } } @@ -352,7 +361,7 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ continue; } - p_callback->call(clipbuf_src[i], closest_B); + p_callback->call(clipbuf_src[i], closest_B, plane_B.get_normal()); } } @@ -431,7 +440,7 @@ static void _generate_contacts_face_circle(const Vector3 *p_points_A, int p_poin continue; } - p_callback->call(contact_point_A, closest_B); + p_callback->call(contact_point_A, closest_B, circle_plane.get_normal()); } } @@ -534,7 +543,7 @@ static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_po continue; } - p_callback->call(contact_point_A, closest_B); + p_callback->call(contact_point_A, closest_B, circle_B_plane.get_normal()); } } @@ -678,7 +687,7 @@ public: return true; } - static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { + static _FORCE_INLINE_ void test_contact_points(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { SeparatorAxisTest<ShapeA, ShapeB, withMargin> *separator = (SeparatorAxisTest<ShapeA, ShapeB, withMargin> *)p_userdata; Vector3 axis = (p_point_B - p_point_A); real_t depth = axis.length(); @@ -802,11 +811,11 @@ static void analytic_sphere_collision(const Vector3 &p_origin_a, real_t p_radius if (p_radius_a < p_radius_b) { Vector3 point_a = p_origin_a - b_to_a * p_radius_a; Vector3 point_b = point_a + b_to_a * overlap; - p_collector->call(point_a, point_b); // Consider adding b_to_a vector + p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector } else { Vector3 point_b = p_origin_b + b_to_a * p_radius_b; Vector3 point_a = point_b - b_to_a * overlap; - p_collector->call(point_a, point_b); // Consider adding b_to_a vector + p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector } } @@ -818,9 +827,9 @@ static void _collision_sphere_sphere(const GodotShape3D *p_a, const Transform3D // Perform an analytic sphere collision between the two spheres analytic_sphere_collision<withMargin>( p_transform_a.origin, - sphere_A->get_radius(), + sphere_A->get_radius() * p_transform_a.basis[0].length(), p_transform_b.origin, - sphere_B->get_radius(), + sphere_B->get_radius() * p_transform_b.basis[0].length(), p_collector, p_margin_a, p_margin_b); @@ -833,7 +842,7 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_ // Find the point on the box nearest to the center of the sphere. - Vector3 center = p_transform_b.xform_inv(p_transform_a.origin); + Vector3 center = p_transform_b.affine_inverse().xform(p_transform_a.origin); Vector3 extents = box_B->get_half_extents(); Vector3 nearest(MIN(MAX(center.x, -extents.x), extents.x), MIN(MAX(center.y, -extents.y), extents.y), @@ -844,7 +853,8 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_ Vector3 delta = nearest - p_transform_a.origin; real_t length = delta.length(); - if (length > sphere_A->get_radius() + p_margin_a + p_margin_b) { + real_t radius = sphere_A->get_radius() * p_transform_a.basis[0].length(); + if (length > radius + p_margin_a + p_margin_b) { return; } p_collector->collided = true; @@ -858,9 +868,9 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_ } else { axis = delta / length; } - Vector3 point_a = p_transform_a.origin + (sphere_A->get_radius() + p_margin_a) * axis; - Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest); - p_collector->call(point_a, point_b); + Vector3 point_a = p_transform_a.origin + (radius + p_margin_a) * axis; + Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest); + p_collector->call(point_a, point_b, axis); } template <bool withMargin> @@ -868,11 +878,12 @@ static void _collision_sphere_capsule(const GodotShape3D *p_a, const Transform3D const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - real_t capsule_B_radius = capsule_B->get_radius(); + real_t scale_A = p_transform_a.basis[0].length(); + real_t scale_B = p_transform_b.basis[0].length(); // Construct the capsule segment (ball-center to ball-center) Vector3 capsule_segment[2]; - Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B_radius); + Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius()); capsule_segment[0] = p_transform_b.origin + capsule_axis; capsule_segment[1] = p_transform_b.origin - capsule_axis; @@ -882,9 +893,9 @@ static void _collision_sphere_capsule(const GodotShape3D *p_a, const Transform3D // Perform an analytic sphere collision between the sphere and the sphere-collider in the capsule analytic_sphere_collision<withMargin>( p_transform_a.origin, - sphere_A->get_radius(), + sphere_A->get_radius() * scale_A, capsule_closest, - capsule_B_radius, + capsule_B->get_radius() * scale_B, p_collector, p_margin_a, p_margin_b); @@ -894,12 +905,12 @@ template <bool withMargin> static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radius_b, real_t p_height_b, const Transform3D &p_transform_a, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { // Find the point on the cylinder nearest to the center of the sphere. - Vector3 center = p_transform_b.xform_inv(p_transform_a.origin); + Vector3 center = p_transform_b.affine_inverse().xform(p_transform_a.origin); Vector3 nearest = center; - real_t radius = p_radius_b; + real_t scale_A = p_transform_a.basis[0].length(); real_t r = Math::sqrt(center.x * center.x + center.z * center.z); - if (r > radius) { - real_t scale = radius / r; + if (r > p_radius_b) { + real_t scale = p_radius_b / r; nearest.x *= scale; nearest.z *= scale; } @@ -911,7 +922,7 @@ static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radiu Vector3 delta = nearest - p_transform_a.origin; real_t length = delta.length(); - if (length > p_radius_a + p_margin_a + p_margin_b) { + if (length > p_radius_a * scale_A + p_margin_a + p_margin_b) { return; } p_collector->collided = true; @@ -925,9 +936,9 @@ static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radiu } else { axis = delta / length; } - Vector3 point_a = p_transform_a.origin + (p_radius_a + p_margin_a) * axis; - Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest); - p_collector->call(point_a, point_b); + Vector3 point_a = p_transform_a.origin + (p_radius_a * scale_A + p_margin_a) * axis; + Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest); + p_collector->call(point_a, point_b, axis); } template <bool withMargin> @@ -1623,14 +1634,14 @@ static void _collision_capsule_capsule(const GodotShape3D *p_a, const Transform3 const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - real_t capsule_A_radius = capsule_A->get_radius(); - real_t capsule_B_radius = capsule_B->get_radius(); + real_t scale_A = p_transform_a.basis[0].length(); + real_t scale_B = p_transform_b.basis[0].length(); // Get the closest points between the capsule segments Vector3 capsule_A_closest; Vector3 capsule_B_closest; - Vector3 capsule_A_axis = p_transform_a.basis.get_column(1) * (capsule_A->get_height() * 0.5 - capsule_A_radius); - Vector3 capsule_B_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B_radius); + Vector3 capsule_A_axis = p_transform_a.basis.get_column(1) * (capsule_A->get_height() * 0.5 - capsule_A->get_radius()); + Vector3 capsule_B_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius()); Geometry3D::get_closest_points_between_segments( p_transform_a.origin + capsule_A_axis, p_transform_a.origin - capsule_A_axis, @@ -1642,9 +1653,9 @@ static void _collision_capsule_capsule(const GodotShape3D *p_a, const Transform3 // Perform the analytic collision between the two closest capsule spheres analytic_sphere_collision<withMargin>( capsule_A_closest, - capsule_A_radius, + capsule_A->get_radius() * scale_A, capsule_B_closest, - capsule_B_radius, + capsule_B->get_radius() * scale_B, p_collector, p_margin_a, p_margin_b); diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp index e8250acb45..b6d8acfbf3 100644 --- a/servers/physics_3d/godot_physics_server_3d.cpp +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -1737,7 +1737,7 @@ void GodotPhysicsServer3D::_update_shapes() { } } -void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { CollCbkData *cbk = static_cast<CollCbkData *>(p_userdata); if (cbk->max == 0) { diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h index 3da0c6debe..040e673dcd 100644 --- a/servers/physics_3d/godot_physics_server_3d.h +++ b/servers/physics_3d/godot_physics_server_3d.h @@ -77,7 +77,7 @@ public: Vector3 *ptr = nullptr; }; - static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); + static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata); virtual RID world_boundary_shape_create() override; virtual RID separation_ray_shape_create() override; diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index c3aad22932..93572965d2 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -445,7 +445,7 @@ struct _RestCallbackData { _RestResultData *other_results = nullptr; }; -static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) { _RestCallbackData *rd = static_cast<_RestCallbackData *>(p_userdata); Vector3 contact_rel = p_point_B - p_point_A; @@ -480,7 +480,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect // Keep this result as separate result. result.len = len; result.contact = p_point_B; - result.normal = contact_rel / len; + result.normal = normal; result.object = rd->object; result.shape = rd->shape; result.local_shape = rd->local_shape; @@ -499,7 +499,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect rd->best_result.len = len; rd->best_result.contact = p_point_B; - rd->best_result.normal = contact_rel / len; + rd->best_result.normal = normal; rd->best_result.object = rd->object; rd->best_result.shape = rd->shape; rd->best_result.local_shape = rd->local_shape; diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h index 62e1eb326d..fd36e7ac10 100644 --- a/servers/rendering/dummy/storage/texture_storage.h +++ b/servers/rendering/dummy/storage/texture_storage.h @@ -154,6 +154,7 @@ public: virtual RID decal_instance_create(RID p_decal) override { return RID(); } virtual void decal_instance_free(RID p_decal_instance) override {} virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {} + virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {} /* RENDER TARGET */ diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 4265ee5518..b9e3c4f303 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -821,6 +821,38 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Vector<int> indices; int point_count = p_points.size(); + + Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline); + + if (p_width < 0) { + if (p_antialiased) { + WARN_PRINT("Antialiasing is not supported for thin polylines drawn using line strips (`p_width < 0`)."); + } + + pline->primitive = RS::PRIMITIVE_LINE_STRIP; + + if (p_colors.size() == 1 || p_colors.size() == point_count) { + pline->polygon.create(indices, p_points, p_colors); + } else { + Vector<Color> colors; + if (p_colors.is_empty()) { + colors.push_back(color); + } else { + colors.resize(point_count); + Color *colors_ptr = colors.ptrw(); + for (int i = 0; i < point_count; i++) { + if (i < p_colors.size()) { + color = p_colors[i]; + } + colors_ptr[i] = color; + } + } + pline->polygon.create(indices, p_points, colors); + } + return; + } + int polyline_point_count = point_count * 2; bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]); @@ -845,9 +877,6 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point } } - Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>(); - ERR_FAIL_COND(!pline); - PackedColorArray colors; PackedVector2Array points; diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 2494ddf631..1106fc4f1e 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -222,7 +222,7 @@ public: void canvas_item_set_update_when_visible(RID p_item, bool p_update); void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false); - void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); + void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false); void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0); void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 93c741fd34..3fd8d55a71 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1480,7 +1480,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); - texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); p_render_data->directional_light_count = directional_light_count; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 816248567b..5d4e3c1ac1 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -632,7 +632,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { uint32_t directional_light_count = 0; uint32_t positional_light_count = 0; light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows); - texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse()); + texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform); p_render_data->directional_light_count = directional_light_count; } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 462b925134..638fe44266 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -455,7 +455,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend light_count++; - if (light_count == MAX_LIGHTS_PER_ITEM) { + if (light_count == MAX_LIGHTS_PER_ITEM - 1) { break; } } diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 673fc25595..33e35a7a64 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -568,8 +568,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged r_directional_light_count = 0; r_positional_light_count = 0; - Plane camera_plane(-p_camera_transform.basis.get_column(Vector3::AXIS_Z).normalized(), p_camera_transform.origin); - omni_light_count = 0; spot_light_count = 0; @@ -720,7 +718,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged } Transform3D light_transform = light_instance->transform; - const real_t distance = camera_plane.distance_to(light_transform.origin); + const real_t distance = p_camera_transform.origin.distance_to(light_transform.origin); if (light->distance_fade) { const float fade_begin = light->distance_fade_begin; @@ -745,7 +743,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged } Transform3D light_transform = light_instance->transform; - const real_t distance = camera_plane.distance_to(light_transform.origin); + const real_t distance = p_camera_transform.origin.distance_to(light_transform.origin); if (light->distance_fade) { const float fade_begin = light->distance_fade_begin; @@ -787,6 +785,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT; LightInstance *light_instance = (i < omni_light_count) ? omni_light_sort[index].light_instance : spot_light_sort[index].light_instance; Light *light = (i < omni_light_count) ? omni_light_sort[index].light : spot_light_sort[index].light; + real_t distance = (i < omni_light_count) ? omni_light_sort[index].depth : spot_light_sort[index].depth; if (using_forward_ids) { forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index); @@ -803,7 +802,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged float fade_begin = 0.0; float fade_shadow = 0.0; float fade_length = 0.0; - real_t distance = 0.0; float fade = 1.0; float shadow_opacity_fade = 1.0; @@ -811,7 +809,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged fade_begin = light->distance_fade_begin; fade_shadow = light->distance_fade_shadow; fade_length = light->distance_fade_length; - distance = camera_plane.distance_to(light_transform.origin); // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. if (distance > fade_begin) { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index 06fda8fa9e..e8d9f486bb 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2206,6 +2206,12 @@ void TextureStorage::decal_instance_set_transform(RID p_decal_instance, const Tr di->transform = p_transform; } +void TextureStorage::decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) { + DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); + ERR_FAIL_COND(!di); + di->sorting_offset = p_sorting_offset; +} + /* DECAL DATA API */ void TextureStorage::free_decal_data() { @@ -2233,7 +2239,7 @@ void TextureStorage::set_max_decals(const uint32_t p_max_decals) { decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size); } -void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) { +void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_xform) { ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton(); Transform3D uv_xform; @@ -2257,7 +2263,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D xform = decal_instance->transform; - real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + real_t distance = p_camera_xform.origin.distance_to(xform.origin); if (decal->distance_fade) { float fade_begin = decal->distance_fade_begin; @@ -2272,7 +2278,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const decal_sort[decal_count].decal_instance = decal_instance; decal_sort[decal_count].decal = decal; - decal_sort[decal_count].depth = distance; + decal_sort[decal_count].depth = distance - decal_instance->sorting_offset; decal_count++; } @@ -2292,11 +2298,10 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const decal_instance->cull_mask = decal->cull_mask; - Transform3D xform = decal_instance->transform; float fade = 1.0; if (decal->distance_fade) { - const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; + const real_t distance = decal_sort[i].depth + decal_instance->sorting_offset; const float fade_begin = decal->distance_fade_begin; const float fade_length = decal->distance_fade_length; @@ -2312,11 +2317,16 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D scale_xform; scale_xform.basis.scale(decal_extents); - Transform3D to_decal_xform = (p_camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse(); + + Transform3D xform = decal_instance->transform; + + Transform3D camera_inverse_xform = p_camera_xform.affine_inverse(); + + Transform3D to_decal_xform = (camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse(); MaterialStorage::store_transform(to_decal_xform, dd.xform); Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized(); - normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine + normal = camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine dd.normal[0] = normal.x; dd.normal[1] = normal.y; @@ -2350,7 +2360,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const dd.normal_rect[2] = rect.size.x; dd.normal_rect[3] = rect.size.y; - Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized(); + Basis normal_xform = camera_inverse_xform.basis * xform.basis.orthonormalized(); MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform); } else { dd.normal_rect[0] = 0; diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 1558342c3b..ea0df0b459 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -258,6 +258,7 @@ private: struct DecalInstance { RID decal; Transform3D transform; + float sorting_offset = 0.0; uint32_t cull_mask = 0; RendererRD::ForwardID forward_id = -1; }; @@ -646,6 +647,7 @@ public: virtual RID decal_instance_create(RID p_decal) override; virtual void decal_instance_free(RID p_decal_instance) override; virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) override; + virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override; _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal_instance) const { DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance); @@ -677,7 +679,7 @@ public: void free_decal_data(); void set_max_decals(const uint32_t p_max_decals); RID get_decal_buffer() { return decal_buffer; } - void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform); + void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_xform); /* RENDER TARGET API */ diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 218bb7b736..de417082f5 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -694,6 +694,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { instance->base_data = decal; decal->instance = RSG::texture_storage->decal_instance_create(p_base); + RSG::texture_storage->decal_instance_set_sorting_offset(decal->instance, instance->sorting_offset); } break; case RS::INSTANCE_LIGHTMAP: { InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); @@ -871,6 +872,9 @@ void RendererSceneCull::instance_set_pivot_data(RID p_instance, float p_sorting_ InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); geom->geometry_instance->set_pivot_data(p_sorting_offset, p_use_aabb_center); + } else if (instance->base_type == RS::INSTANCE_DECAL && instance->base_data) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data); + RSG::texture_storage->decal_instance_set_sorting_offset(decal->instance, instance->sorting_offset); } } @@ -2824,7 +2828,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); ERR_FAIL_NULL(geom->geometry_instance); + cull_data.cull->lock.lock(); geom->geometry_instance->set_softshadow_projector_pairing(geom->softshadow_count > 0, geom->projector_count > 0); + cull_data.cull->lock.unlock(); idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY); } @@ -2891,7 +2897,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); } ERR_FAIL_NULL(geom->geometry_instance); + cull_data.cull->lock.lock(); geom->geometry_instance->set_lightmap_capture(sh); + cull_data.cull->lock.unlock(); idata.instance->last_frame_pass = frame_number; } diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 5ecc38a63b..ba7ffda00a 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5402,7 +5402,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (identifier == "SCREEN_TEXTURE" || identifier == "DEPTH_TEXTURE" || identifier == "NORMAL_ROUGHNESS_TEXTURE") { String name = String(identifier); String name_lower = name.to_lower(); - _set_error(vformat(RTR("%s has been removed in favor of using hint_%s with a uniform.\nTo continue with minimal code changes add 'uniform sampler2D %s : hint_%s, filter_linear_mipmaps;' near the top of your shader."), name, name_lower, name, name_lower)); + _set_error(vformat(RTR("%s has been removed in favor of using hint_%s with a uniform.\nTo continue with minimal code changes add 'uniform sampler2D %s : hint_%s, filter_linear_mipmap;' near the top of your shader."), name, name_lower, name, name_lower)); return nullptr; } _set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier))); @@ -8697,14 +8697,17 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f case TK_HINT_SCREEN_TEXTURE: { new_hint = ShaderNode::Uniform::HINT_SCREEN_TEXTURE; --texture_uniforms; + --texture_binding; } break; case TK_HINT_NORMAL_ROUGHNESS_TEXTURE: { new_hint = ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE; --texture_uniforms; + --texture_binding; } break; case TK_HINT_DEPTH_TEXTURE: { new_hint = ShaderNode::Uniform::HINT_DEPTH_TEXTURE; --texture_uniforms; + --texture_binding; } break; case TK_FILTER_NEAREST: { new_filter = FILTER_NEAREST; diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp index 40c8acffe5..ccbf5defa2 100644 --- a/servers/rendering/shader_preprocessor.cpp +++ b/servers/rendering/shader_preprocessor.cpp @@ -1081,21 +1081,17 @@ ShaderPreprocessor::Define *ShaderPreprocessor::create_define(const String &p_bo return define; } -void ShaderPreprocessor::clear() { - if (state_owner && state != nullptr) { +void ShaderPreprocessor::clear_state() { + if (state != nullptr) { for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) { memdelete(E->get()); } - - memdelete(state); + state->defines.clear(); } - state_owner = false; state = nullptr; } Error ShaderPreprocessor::preprocess(State *p_state, const String &p_code, String &r_result) { - clear(); - output.clear(); state = p_state; @@ -1242,6 +1238,9 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen } } } + + clear_state(); + return err; } @@ -1273,5 +1272,4 @@ ShaderPreprocessor::ShaderPreprocessor() { } ShaderPreprocessor::~ShaderPreprocessor() { - clear(); } diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h index f5902c64ca..6e5533c575 100644 --- a/servers/rendering/shader_preprocessor.h +++ b/servers/rendering/shader_preprocessor.h @@ -167,7 +167,6 @@ private: private: LocalVector<char32_t> output; State *state = nullptr; - bool state_owner = false; private: static bool is_char_word(char32_t p_char); @@ -211,7 +210,7 @@ private: static Define *create_define(const String &p_body); - void clear(); + void clear_state(); Error preprocess(State *p_state, const String &p_code, String &r_result); diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h index 92149b0064..4c4a84d04e 100644 --- a/servers/rendering/storage/texture_storage.h +++ b/servers/rendering/storage/texture_storage.h @@ -127,6 +127,7 @@ public: virtual RID decal_instance_create(RID p_decal) = 0; virtual void decal_instance_free(RID p_decal_instance) = 0; virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) = 0; + virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) = 0; /* RENDER TARGET */ diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index e24b2af976..675db63b9a 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -996,6 +996,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa if (index_array_len) { List<Variant> keys; p_lods.get_key_list(&keys); + keys.sort(); // otherwise lod levels may get skipped for (const Variant &E : keys) { float distance = E; ERR_CONTINUE(distance <= 0.0); @@ -1826,6 +1827,7 @@ void RenderingServer::_bind_methods() { BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_2D_VERTICES); BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_DYNAMIC_UPDATE); BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS); + BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY); BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); @@ -2593,7 +2595,7 @@ void RenderingServer::_bind_methods() { /* Primitives */ ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(-1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(-1.0), DEFVAL(false)); ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect); ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false)); @@ -2961,9 +2963,9 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1"), 64); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)"), 1); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000); + GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"), 512); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 4b51099ef0..231139e9df 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1335,7 +1335,7 @@ public: }; virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false) = 0; - virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0; + virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false) = 0; virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0) = 0; virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0; virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0; diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 997b83e32d..cbf37f25d6 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -1373,8 +1373,8 @@ String TextServerExtension::string_to_lower(const String &p_string, const String return p_string; } -TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { - TypedArray<Vector2i> ret; +TypedArray<Vector3i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { + TypedArray<Vector3i> ret; GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret); return ret; } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index fb784f5471..8536836983 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -521,8 +521,8 @@ public: GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &); GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &); - TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; - GDVIRTUAL3RC(TypedArray<Vector2i>, _parse_structured_text, StructuredTextParser, const Array &, const String &); + TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &); virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override; virtual bool spoof_check(const String &p_string) const override; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index d339533688..027109b67d 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -483,6 +483,7 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(DIRECTION_AUTO); BIND_ENUM_CONSTANT(DIRECTION_LTR); BIND_ENUM_CONSTANT(DIRECTION_RTL); + BIND_ENUM_CONSTANT(DIRECTION_INHERITED); /* Orientation */ BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL); @@ -599,7 +600,7 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(STRUCTURED_TEXT_FILE); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_EMAIL); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST); - BIND_ENUM_CONSTANT(STRUCTURED_TEXT_NONE); + BIND_ENUM_CONSTANT(STRUCTURED_TEXT_GDSCRIPT); BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM); } @@ -1692,22 +1693,22 @@ String TextServer::strip_diacritics(const String &p_string) const { return result; } -TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { - TypedArray<Vector2i> ret; +TypedArray<Vector3i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { + TypedArray<Vector3i> ret; switch (p_parser_type) { case STRUCTURED_TEXT_URI: { int prev = 0; for (int i = 0; i < p_text.length(); i++) { if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == '.') || (p_text[i] == ':') || (p_text[i] == '&') || (p_text[i] == '=') || (p_text[i] == '@') || (p_text[i] == '?') || (p_text[i] == '#')) { if (prev != i) { - ret.push_back(Vector2i(prev, i)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); } - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } } if (prev != p_text.length()) { - ret.push_back(Vector2i(prev, p_text.length())); + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); } } break; case STRUCTURED_TEXT_FILE: { @@ -1715,14 +1716,14 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa for (int i = 0; i < p_text.length(); i++) { if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == ':')) { if (prev != i) { - ret.push_back(Vector2i(prev, i)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); } - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } } if (prev != p_text.length()) { - ret.push_back(Vector2i(prev, p_text.length())); + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); } } break; case STRUCTURED_TEXT_EMAIL: { @@ -1731,19 +1732,19 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa for (int i = 0; i < p_text.length(); i++) { if ((p_text[i] == '@') && local) { // Add full "local" as single context. local = false; - ret.push_back(Vector2i(prev, i)); - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context. if (prev != i) { - ret.push_back(Vector2i(prev, i)); + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); } - ret.push_back(Vector2i(i, i + 1)); + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); prev = i + 1; } } if (prev != p_text.length()) { - ret.push_back(Vector2i(prev, p_text.length())); + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); } } break; case STRUCTURED_TEXT_LIST: { @@ -1752,18 +1753,97 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa int prev = 0; for (int i = 0; i < tags.size(); i++) { if (prev != i) { - ret.push_back(Vector2i(prev, prev + tags[i].length())); + ret.push_back(Vector3i(prev, prev + tags[i].length(), TextServer::DIRECTION_INHERITED)); } - ret.push_back(Vector2i(prev + tags[i].length(), prev + tags[i].length() + 1)); + ret.push_back(Vector3i(prev + tags[i].length(), prev + tags[i].length() + 1, TextServer::DIRECTION_INHERITED)); prev = prev + tags[i].length() + 1; } } } break; + case STRUCTURED_TEXT_GDSCRIPT: { + bool in_string_literal = false; + bool in_string_literal_single = false; + bool in_id = false; + + int prev = 0; + for (int i = 0; i < p_text.length(); i++) { + char32_t c = p_text[i]; + if (in_string_literal) { + if (c == '\\') { + i++; + continue; // Skip escaped chars. + } else if (c == '\"') { + // String literal end, push string and ". + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal = false; + } + } else if (in_string_literal_single) { + if (c == '\\') { + i++; + continue; // Skip escaped chars. + } else if (c == '\'') { + // String literal end, push string and '. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal_single = false; + } + } else if (in_id) { + if (!is_unicode_identifier_continue(c)) { + // End of id, push id. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i; + in_id = false; + } + } else if (is_unicode_identifier_start(c)) { + // Start of new id, push prev element. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i; + in_id = true; + } else if (c == '\"') { + // String literal start, push prev element and ". + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal = true; + } else if (c == '\'') { + // String literal start, push prev element and '. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + in_string_literal_single = true; + } else if (c == '#') { + // Start of comment, push prev element and #, skip the rest of the text. + if (prev != i) { + ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); + } + prev = i + 1; + ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); + break; + } + } + if (prev < p_text.length()) { + ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); + } + } break; case STRUCTURED_TEXT_CUSTOM: - case STRUCTURED_TEXT_NONE: case STRUCTURED_TEXT_DEFAULT: default: { - ret.push_back(Vector2i(0, p_text.length())); + ret.push_back(Vector3i(0, p_text.length(), TextServer::DIRECTION_INHERITED)); } } return ret; diff --git a/servers/text_server.h b/servers/text_server.h index a56c7d8b23..a91d367e97 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -65,7 +65,8 @@ public: enum Direction { DIRECTION_AUTO, DIRECTION_LTR, - DIRECTION_RTL + DIRECTION_RTL, + DIRECTION_INHERITED, }; enum Orientation { @@ -198,7 +199,7 @@ public: STRUCTURED_TEXT_FILE, STRUCTURED_TEXT_EMAIL, STRUCTURED_TEXT_LIST, - STRUCTURED_TEXT_NONE, + STRUCTURED_TEXT_GDSCRIPT, STRUCTURED_TEXT_CUSTOM }; @@ -505,7 +506,7 @@ public: virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0; virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0; - TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; + TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; virtual void cleanup() {} |