diff --git a/gdnative-core/src/core_types/transform2d.rs b/gdnative-core/src/core_types/transform2d.rs index 03e411c60..76092af31 100644 --- a/gdnative-core/src/core_types/transform2d.rs +++ b/gdnative-core/src/core_types/transform2d.rs @@ -1,8 +1,8 @@ use super::Vector2; /// A 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations. It can represent -/// transformations such as translation, rotation, or scaling. It consists of a three -/// Vector2 values: x, y, and the origin. +/// transformations such as translation, rotation, or scaling. It consists of three +/// Vector2 values: x axis, y axis, and the origin. #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] @@ -11,7 +11,7 @@ pub struct Transform2D { /// moving on the X axis in the coordinate space of this transform pub x: Vector2, /// The y basis vector of the transform. Objects will move along this vector when - /// moving on the Y axis in the coordinate space of this transform + /// moving on the Y axis in the coordinate space of this transform. pub y: Vector2, /// The origin of the transform. The coordinate space defined by this transform /// starts at this point. @@ -213,4 +213,62 @@ impl Transform2D { && self.y.is_equal_approx(other.y) && self.origin.is_equal_approx(other.origin) } + + /// Internal API for converting to `sys` representation. Makes it possible to remove + /// `transmute`s elsewhere. + #[doc(hidden)] + #[inline] + pub fn sys(&self) -> *const sys::godot_transform2d { + self as *const _ as *const _ + } } + +fn test_transform2d_behavior_impl() { + let api = crate::private::get_api(); + + // This test compares the Transform2D implementation against the Godot API, + // making sure behavior is consistent between the two. + + let new_transform_rust = Transform2D::from_axis_origin( + Vector2::new(42.0, 0.0), + Vector2::new(0.0, 23.0), + Vector2::new(5.0, 8.0), + ); + + // constructors yield same results + + let new_transform_godot = unsafe { + let mut tr = Transform2D::IDENTITY; + let tr_p = &mut tr as *mut _ as *mut sys::godot_transform2d; + let x_axis = Vector2::new(42.0, 0.0); + let y_axis = Vector2::new(0.0, 23.0); + let origin = Vector2::new(5.0, 8.0); + (api.godot_transform2d_new_axis_origin)(tr_p, x_axis.sys(), y_axis.sys(), origin.sys()); + tr + }; + + assert_eq!( + new_transform_rust, new_transform_godot, + "Newly constructed transforms should be identical" + ); + + // Affine inverse + + let rust_inverse = new_transform_rust.affine_inverse(); + let godot_inverse = unsafe { + std::mem::transmute::<_, Transform2D>((api.godot_transform2d_affine_inverse)( + new_transform_rust.sys(), + )) + }; + + assert_eq!( + rust_inverse, godot_inverse, + "Affine inverse operation should be identical" + ); +} + +godot_test!( + test_transform2d_behavior { + test_transform2d_behavior_impl() + } +); diff --git a/test/src/lib.rs b/test/src/lib.rs index af69adb19..593444129 100644 --- a/test/src/lib.rs +++ b/test/src/lib.rs @@ -56,6 +56,7 @@ pub extern "C" fn run_tests( status &= gdnative::core_types::test_vector2_array_debug(); status &= gdnative::core_types::test_vector3_array_access(); status &= gdnative::core_types::test_vector3_array_debug(); + status &= gdnative::core_types::test_transform2d_behavior(); status &= test_underscore_method_binding(); status &= test_rust_class_construction();