Skip to main content

lunar_math/
macros.rs

1//! convenience macros for common math types.
2
3/// create a `Transform` from components.
4///
5/// # example
6///
7/// ```ignore
8/// use lunar_math::{transform, Vec2};
9///
10/// let t = transform!(pos: Vec2::new(10.0, 20.0), rot: 0.5, scale: Vec2::ONE);
11/// ```
12#[macro_export]
13macro_rules! transform {
14	(pos: $pos:expr, rot: $rot:expr, scale: $scale:expr) => {
15		$crate::Transform {
16			translation: $crate::Vec2::new($pos.x, $pos.y),
17			rotation: $rot,
18			scale: $scale,
19		}
20	};
21	(x: $x:expr, y: $y:expr) => {
22		$crate::Transform {
23			translation: $crate::Vec2::new($x, $y),
24			rotation: 0.0,
25			scale: $crate::Vec2::ONE,
26		}
27	};
28	(pos: $pos:expr) => {
29		$crate::Transform {
30			translation: $crate::Vec2::new($pos.x, $pos.y),
31			rotation: 0.0,
32			scale: $crate::Vec2::ONE,
33		}
34	};
35}
36
37/// create a `Color` from components.
38///
39/// # example
40///
41/// ```ignore
42/// use lunar_math::color;
43///
44/// let c = color!(r: 1.0, g: 0.0, b: 0.0);
45/// let d = color!(r: 1.0, g: 0.0, b: 0.0, a: 0.5);
46/// ```
47#[macro_export]
48macro_rules! color {
49	(r: $r:expr, g: $g:expr, b: $b:expr) => {
50		$crate::Color {
51			r: $r,
52			g: $g,
53			b: $b,
54			a: 1.0,
55		}
56	};
57	(r: $r:expr, g: $g:expr, b: $b:expr, a: $a:expr) => {
58		$crate::Color {
59			r: $r,
60			g: $g,
61			b: $b,
62			a: $a,
63		}
64	};
65	(hex: $hex:expr) => {{
66		let hex = $hex;
67		let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
68		let g = ((hex >> 8) & 0xFF) as f32 / 255.0;
69		let b = (hex & 0xFF) as f32 / 255.0;
70		$crate::Color { r, g, b, a: 1.0 }
71	}};
72}
73
74/// create a `Rect` from components.
75///
76/// # example
77///
78/// ```ignore
79/// use lunar_math::rect;
80///
81/// let r = rect!(x: 0, y: 0, w: 100, h: 50);
82/// ```
83#[macro_export]
84macro_rules! rect {
85	(x: $x:expr, y: $y:expr, w: $w:expr, h: $h:expr) => {
86		$crate::Rect {
87			x: $x,
88			y: $y,
89			w: $w,
90			h: $h,
91		}
92	};
93	(pos: $pos:expr, size: $size:expr) => {
94		$crate::Rect {
95			x: $pos.x,
96			y: $pos.y,
97			w: $size.x,
98			h: $size.y,
99		}
100	};
101}
102
103/// convenience wrapper for creating ecs query types.
104///
105/// this macro simplifies common query patterns by wrapping `bevy_ecs` query filters
106/// into a single expression. it is designed to be used in system function signatures.
107///
108/// # example
109///
110/// ```ignore
111/// use lunar_math::query;
112/// use bevy_ecs::prelude::Query;
113///
114/// // query for entities with Position and Velocity
115/// fn my_system(query: query!(Position, Velocity)) {
116///     for (pos, vel) in query.iter() {
117///         // ...
118///     }
119/// }
120///
121/// // query with filters
122/// fn filtered(query: query!(Position, with: Player, without: Dead, changed: Velocity)) {
123///     // ...
124/// }
125/// ```
126#[macro_export]
127macro_rules! query {
128    // query!(A, B)
129    ($($component:ty),+ $(,)?) => {
130        bevy_ecs::prelude::Query<($(& $component),+)>
131    };
132    // query!(A, B, with: C)
133    ($($component:ty),+, with: $with:ty $(,)?) => {
134        bevy_ecs::prelude::Query<($(& $component),+), bevy_ecs::prelude::With<$with>>
135    };
136    // query!(A, B, without: C)
137    ($($component:ty),+, without: $without:ty $(,)?) => {
138        bevy_ecs::prelude::Query<($(& $component),+), bevy_ecs::prelude::Without<$without>>
139    };
140    // query!(A, B, changed: C)
141    ($($component:ty),+, changed: $changed:ty $(,)?) => {
142        bevy_ecs::prelude::Query<($(& $component),+), bevy_ecs::prelude::Changed<$changed>>
143    };
144    // query!(A, B, with: C, without: D)
145    ($($component:ty),+, with: $with:ty, without: $without:ty $(,)?) => {
146        bevy_ecs::prelude::Query<($(& $component),+), (bevy_ecs::prelude::With<$with>, bevy_ecs::prelude::Without<$without>)>
147    };
148    // query!(A, B, with: C, changed: D)
149    ($($component:ty),+, with: $with:ty, changed: $changed:ty $(,)?) => {
150        bevy_ecs::prelude::Query<($(& $component),+), (bevy_ecs::prelude::With<$with>, bevy_ecs::prelude::Changed<$changed>)>
151    };
152    // query!(A, B, without: C, changed: D)
153    ($($component:ty),+, without: $without:ty, changed: $changed:ty $(,)?) => {
154        bevy_ecs::prelude::Query<($(& $component),+), (bevy_ecs::prelude::Without<$without>, bevy_ecs::prelude::Changed<$changed>)>
155    };
156    // query!(A, B, with: C, without: D, changed: E)
157    ($($component:ty),+, with: $with:ty, without: $without:ty, changed: $changed:ty $(,)?) => {
158        bevy_ecs::prelude::Query<($(& $component),+), (bevy_ecs::prelude::With<$with>, bevy_ecs::prelude::Without<$without>, bevy_ecs::prelude::Changed<$changed>)>
159    };
160}
161
162#[cfg(test)]
163mod macro_tests {
164	#[test]
165	fn transform_macro_full() {
166		let t = transform!(pos: crate::Vec2::new(1.0, 2.0), rot: 3.0, scale: crate::Vec2::new(4.0, 5.0));
167		assert_eq!(t.translation.x, 1.0);
168		assert_eq!(t.translation.y, 2.0);
169		assert_eq!(t.rotation, 3.0);
170		assert_eq!(t.scale.x, 4.0);
171		assert_eq!(t.scale.y, 5.0);
172	}
173
174	#[test]
175	fn transform_macro_xy() {
176		let t = transform!(x: 10.0, y: 20.0);
177		assert_eq!(t.translation.x, 10.0);
178		assert_eq!(t.translation.y, 20.0);
179		assert_eq!(t.rotation, 0.0);
180		assert_eq!(t.scale, crate::Vec2::ONE);
181	}
182
183	#[test]
184	fn transform_macro_pos_only() {
185		let t = transform!(pos: crate::Vec2::new(5.0, 6.0));
186		assert_eq!(t.translation.x, 5.0);
187		assert_eq!(t.rotation, 0.0);
188	}
189
190	#[test]
191	fn color_macro_rgb() {
192		let c = color!(r: 1.0, g: 0.5, b: 0.0);
193		assert_eq!(c.r, 1.0);
194		assert_eq!(c.g, 0.5);
195		assert_eq!(c.b, 0.0);
196		assert_eq!(c.a, 1.0);
197	}
198
199	#[test]
200	fn color_macro_rgba() {
201		let c = color!(r: 0.5, g: 0.5, b: 0.5, a: 0.25);
202		assert_eq!(c.a, 0.25);
203	}
204
205	#[test]
206	fn color_macro_hex() {
207		let c = color!(hex: 0xFF8800);
208		assert!((c.r - 1.0).abs() < 0.001);
209		assert!((c.g - 0.533).abs() < 0.001);
210		assert!((c.b - 0.0).abs() < 0.001);
211	}
212
213	#[test]
214	fn rect_macro_xywh() {
215		let r = rect!(x: 0.0, y: 10.0, w: 100.0, h: 50.0);
216		assert_eq!(r.x, 0.0);
217		assert_eq!(r.y, 10.0);
218		assert_eq!(r.w, 100.0);
219		assert_eq!(r.h, 50.0);
220	}
221
222	#[test]
223	fn rect_macro_pos_size() {
224		let r = rect!(pos: crate::Vec2::new(5.0, 5.0), size: crate::Vec2::new(10.0, 20.0));
225		assert_eq!(r.x, 5.0);
226		assert_eq!(r.y, 5.0);
227		assert_eq!(r.w, 10.0);
228		assert_eq!(r.h, 20.0);
229	}
230}