From 77db46198a1af6b6255ef6e9dd15ad6e4bb5269f Mon Sep 17 00:00:00 2001 From: Connor Date: Tue, 30 Dec 2025 23:38:55 +0900 Subject: [PATCH] external library for math types --- Cargo.lock | 10 ++ Cargo.toml | 3 + src/property/mod.rs | 18 ++-- src/types/transform.rs | 22 ++--- src/types/values.rs | 203 ++++------------------------------------- 5 files changed, 50 insertions(+), 206 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 859eec3..d8bb638 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ name = "cursebreaker-parser" version = "0.1.0" dependencies = [ + "glam", "indexmap", "pretty_assertions", "regex", @@ -35,6 +36,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "glam" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee" +dependencies = [ + "serde", +] + [[package]] name = "hashbrown" version = "0.16.1" diff --git a/Cargo.toml b/Cargo.toml index db39b2e..8489e9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,9 @@ indexmap = { version = "2.1", features = ["serde"] } # Regex for parsing regex = "1.10" +# Math types (Vector2, Vector3, Quaternion, etc.) +glam = { version = "0.29", features = ["serde"] } + [dev-dependencies] # Testing utilities pretty_assertions = "1.4" diff --git a/src/property/mod.rs b/src/property/mod.rs index 0cf6e72..9470268 100644 --- a/src/property/mod.rs +++ b/src/property/mod.rs @@ -185,7 +185,7 @@ impl fmt::Display for PropertyValue { PropertyValue::Null => write!(f, "null"), PropertyValue::Vector2(v) => write!(f, "({}, {})", v.x, v.y), PropertyValue::Vector3(v) => write!(f, "({}, {}, {})", v.x, v.y, v.z), - PropertyValue::Color(c) => write!(f, "rgba({}, {}, {}, {})", c.r, c.g, c.b, c.a), + PropertyValue::Color(c) => write!(f, "rgba({}, {}, {}, {})", c.x, c.y, c.z, c.w), PropertyValue::Quaternion(q) => write!(f, "({}, {}, {}, {})", q.x, q.y, q.z, q.w), PropertyValue::FileRef(r) => write!(f, "{{fileID: {}}}", r.file_id), PropertyValue::ExternalRef(r) => write!(f, "{{guid: {}, type: {}}}", r.guid, r.type_id), @@ -324,6 +324,7 @@ fn try_convert_unity_type( if let (Some(r), Some(g), Some(b), Some(a)) = (get_f32("r"), get_f32("g"), get_f32("b"), get_f32("a")) { + // Color is Vec4 where (r,g,b,a) maps to (x,y,z,w) return Ok(Some(PropertyValue::Color(Color::new(r, g, b, a)))); } } @@ -338,7 +339,8 @@ fn try_convert_unity_type( if let (Some(x), Some(y), Some(z), Some(w)) = (get_f32("x"), get_f32("y"), get_f32("z"), get_f32("w")) { - return Ok(Some(PropertyValue::Quaternion(Quaternion::new( + // Quaternion uses from_xyzw constructor + return Ok(Some(PropertyValue::Quaternion(Quaternion::from_xyzw( x, y, z, w, )))); } @@ -427,10 +429,10 @@ mod tests { let result = convert_yaml_value(&yaml).unwrap(); if let PropertyValue::Color(c) = result { - assert_eq!(c.r, 1.0); - assert_eq!(c.g, 0.5); - assert_eq!(c.b, 0.0); - assert_eq!(c.a, 1.0); + assert_eq!(c.x, 1.0); // r + assert_eq!(c.y, 0.5); // g + assert_eq!(c.z, 0.0); // b + assert_eq!(c.w, 1.0); // a } else { panic!("Expected Color, got {:?}", result); } @@ -518,8 +520,8 @@ mod tests { fn test_type_checks() { assert!(PropertyValue::Null.is_null()); assert!(PropertyValue::Array(vec![]).is_array()); - assert!(PropertyValue::Vector3(Vector3::zero()).is_vector3()); - assert!(PropertyValue::Color(Color::white()).is_color()); + assert!(PropertyValue::Vector3(Vector3::ZERO).is_vector3()); + assert!(PropertyValue::Color(Color::ONE).is_color()); } #[test] diff --git a/src/types/transform.rs b/src/types/transform.rs index 30f2064..537bac9 100644 --- a/src/types/transform.rs +++ b/src/types/transform.rs @@ -242,11 +242,11 @@ mod tests { ); transform_props.insert( "m_LocalRotation".to_string(), - PropertyValue::Quaternion(Quaternion::identity()), + PropertyValue::Quaternion(Quaternion::IDENTITY), ); transform_props.insert( "m_LocalScale".to_string(), - PropertyValue::Vector3(Vector3::one()), + PropertyValue::Vector3(Vector3::ONE), ); transform_props.insert( "m_GameObject".to_string(), @@ -270,27 +270,27 @@ mod tests { let mut rect_props = IndexMap::new(); rect_props.insert( "m_LocalPosition".to_string(), - PropertyValue::Vector3(Vector3::zero()), + PropertyValue::Vector3(Vector3::ZERO), ); rect_props.insert( "m_LocalRotation".to_string(), - PropertyValue::Quaternion(Quaternion::identity()), + PropertyValue::Quaternion(Quaternion::IDENTITY), ); rect_props.insert( "m_LocalScale".to_string(), - PropertyValue::Vector3(Vector3::one()), + PropertyValue::Vector3(Vector3::ONE), ); rect_props.insert( "m_AnchorMin".to_string(), - PropertyValue::Vector2(Vector2::zero()), + PropertyValue::Vector2(Vector2::ZERO), ); rect_props.insert( "m_AnchorMax".to_string(), - PropertyValue::Vector2(Vector2::one()), + PropertyValue::Vector2(Vector2::ONE), ); rect_props.insert( "m_AnchoredPosition".to_string(), - PropertyValue::Vector2(Vector2::zero()), + PropertyValue::Vector2(Vector2::ZERO), ); rect_props.insert( "m_SizeDelta".to_string(), @@ -341,7 +341,7 @@ mod tests { let doc = create_test_transform(); let transform = Transform::new(&doc).unwrap(); let scale = transform.local_scale().unwrap(); - assert_eq!(scale, &Vector3::one()); + assert_eq!(scale, &Vector3::ONE); } #[test] @@ -356,7 +356,7 @@ mod tests { let doc = create_test_rect_transform(); let rect_transform = RectTransform::new(&doc).unwrap(); let anchor_min = rect_transform.anchor_min().unwrap(); - assert_eq!(anchor_min, &Vector2::zero()); + assert_eq!(anchor_min, &Vector2::ZERO); } #[test] @@ -364,7 +364,7 @@ mod tests { let doc = create_test_rect_transform(); let rect_transform = RectTransform::new(&doc).unwrap(); let anchor_max = rect_transform.anchor_max().unwrap(); - assert_eq!(anchor_max, &Vector2::one()); + assert_eq!(anchor_max, &Vector2::ONE); } #[test] diff --git a/src/types/values.rs b/src/types/values.rs index 59d10b8..d4fda34 100644 --- a/src/types/values.rs +++ b/src/types/values.rs @@ -2,176 +2,8 @@ use super::FileID; -/// A 2D vector used in Unity -/// -/// # Examples -/// -/// ``` -/// use cursebreaker_parser::Vector2; -/// -/// let v = Vector2::new(1.0, 2.0); -/// assert_eq!(v.x, 1.0); -/// assert_eq!(v.y, 2.0); -/// ``` -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Vector2 { - pub x: f32, - pub y: f32, -} - -impl Vector2 { - /// Create a new Vector2 - pub fn new(x: f32, y: f32) -> Self { - Self { x, y } - } - - /// Create a zero vector (0, 0) - pub fn zero() -> Self { - Self::new(0.0, 0.0) - } - - /// Create a one vector (1, 1) - pub fn one() -> Self { - Self::new(1.0, 1.0) - } -} - -/// A 3D vector used in Unity for positions, scales, etc. -/// -/// # Examples -/// -/// ``` -/// use cursebreaker_parser::Vector3; -/// -/// let v = Vector3::new(1.0, 2.0, 3.0); -/// assert_eq!(v.x, 1.0); -/// assert_eq!(v.y, 2.0); -/// assert_eq!(v.z, 3.0); -/// ``` -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Vector3 { - pub x: f32, - pub y: f32, - pub z: f32, -} - -impl Vector3 { - /// Create a new Vector3 - pub fn new(x: f32, y: f32, z: f32) -> Self { - Self { x, y, z } - } - - /// Create a zero vector (0, 0, 0) - pub fn zero() -> Self { - Self::new(0.0, 0.0, 0.0) - } - - /// Create a one vector (1, 1, 1) - pub fn one() -> Self { - Self::new(1.0, 1.0, 1.0) - } - - /// Create an up vector (0, 1, 0) - pub fn up() -> Self { - Self::new(0.0, 1.0, 0.0) - } - - /// Create a forward vector (0, 0, 1) - pub fn forward() -> Self { - Self::new(0.0, 0.0, 1.0) - } - - /// Create a right vector (1, 0, 0) - pub fn right() -> Self { - Self::new(1.0, 0.0, 0.0) - } -} - -/// A color with RGBA components -/// -/// # Examples -/// -/// ``` -/// use cursebreaker_parser::Color; -/// -/// let c = Color::new(1.0, 0.5, 0.0, 1.0); -/// assert_eq!(c.r, 1.0); -/// assert_eq!(c.a, 1.0); -/// ``` -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Color { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} - -impl Color { - /// Create a new Color - pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self { - Self { r, g, b, a } - } - - /// Create a white color (1, 1, 1, 1) - pub fn white() -> Self { - Self::new(1.0, 1.0, 1.0, 1.0) - } - - /// Create a black color (0, 0, 0, 1) - pub fn black() -> Self { - Self::new(0.0, 0.0, 0.0, 1.0) - } - - /// Create a transparent color (0, 0, 0, 0) - pub fn clear() -> Self { - Self::new(0.0, 0.0, 0.0, 0.0) - } - - /// Create a red color (1, 0, 0, 1) - pub fn red() -> Self { - Self::new(1.0, 0.0, 0.0, 1.0) - } - - /// Create a green color (0, 1, 0, 1) - pub fn green() -> Self { - Self::new(0.0, 1.0, 0.0, 1.0) - } - - /// Create a blue color (0, 0, 1, 1) - pub fn blue() -> Self { - Self::new(0.0, 0.0, 1.0, 1.0) - } -} - -/// A quaternion used for rotations in Unity -/// -/// # Examples -/// -/// ``` -/// use cursebreaker_parser::Quaternion; -/// -/// let q = Quaternion::identity(); -/// assert_eq!(q.w, 1.0); -/// ``` -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Quaternion { - pub x: f32, - pub y: f32, - pub z: f32, - pub w: f32, -} - -impl Quaternion { - /// Create a new Quaternion - pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self { - Self { x, y, z, w } - } - - /// Create an identity quaternion (0, 0, 0, 1) - pub fn identity() -> Self { - Self::new(0.0, 0.0, 0.0, 1.0) - } -} +// Re-export glam types for Unity compatibility +pub use glam::{Quat as Quaternion, Vec2 as Vector2, Vec3 as Vector3, Vec4 as Color}; /// A reference to another Unity object by file ID /// @@ -232,7 +64,7 @@ mod tests { #[test] fn test_vector2_zero() { - let v = Vector2::zero(); + let v = Vector2::ZERO; assert_eq!(v, Vector2::new(0.0, 0.0)); } @@ -246,46 +78,43 @@ mod tests { #[test] fn test_vector3_zero() { - let v = Vector3::zero(); + let v = Vector3::ZERO; assert_eq!(v, Vector3::new(0.0, 0.0, 0.0)); } #[test] fn test_vector3_directions() { - assert_eq!(Vector3::up(), Vector3::new(0.0, 1.0, 0.0)); - assert_eq!(Vector3::forward(), Vector3::new(0.0, 0.0, 1.0)); - assert_eq!(Vector3::right(), Vector3::new(1.0, 0.0, 0.0)); + assert_eq!(Vector3::Y, Vector3::new(0.0, 1.0, 0.0)); + assert_eq!(Vector3::Z, Vector3::new(0.0, 0.0, 1.0)); + assert_eq!(Vector3::X, Vector3::new(1.0, 0.0, 0.0)); } #[test] fn test_color_creation() { let c = Color::new(1.0, 0.5, 0.0, 1.0); - assert_eq!(c.r, 1.0); - assert_eq!(c.g, 0.5); - assert_eq!(c.b, 0.0); - assert_eq!(c.a, 1.0); + assert_eq!(c.x, 1.0); // r + assert_eq!(c.y, 0.5); // g + assert_eq!(c.z, 0.0); // b + assert_eq!(c.w, 1.0); // a } #[test] fn test_color_presets() { - assert_eq!(Color::white(), Color::new(1.0, 1.0, 1.0, 1.0)); - assert_eq!(Color::black(), Color::new(0.0, 0.0, 0.0, 1.0)); - assert_eq!(Color::red(), Color::new(1.0, 0.0, 0.0, 1.0)); - assert_eq!(Color::green(), Color::new(0.0, 1.0, 0.0, 1.0)); - assert_eq!(Color::blue(), Color::new(0.0, 0.0, 1.0, 1.0)); + assert_eq!(Color::ONE, Color::new(1.0, 1.0, 1.0, 1.0)); // white + assert_eq!(Color::new(0.0, 0.0, 0.0, 1.0), Color::new(0.0, 0.0, 0.0, 1.0)); // black } #[test] fn test_quaternion_creation() { - let q = Quaternion::new(0.0, 0.0, 0.0, 1.0); + let q = Quaternion::from_xyzw(0.0, 0.0, 0.0, 1.0); assert_eq!(q.x, 0.0); assert_eq!(q.w, 1.0); } #[test] fn test_quaternion_identity() { - let q = Quaternion::identity(); - assert_eq!(q, Quaternion::new(0.0, 0.0, 0.0, 1.0)); + let q = Quaternion::IDENTITY; + assert_eq!(q, Quaternion::from_xyzw(0.0, 0.0, 0.0, 1.0)); } #[test]