1use std::ops::{Mul, Neg};
2
3use bevy::ecs::entity::Entity;
4use bevy::ecs::{component::Component, reflect::ReflectComponent};
5use bevy::math::{Quat, Rect, Vec2};
6use bevy::reflect::{std_traits::ReflectDefault, Reflect, ReflectDeserialize, ReflectSerialize};
7use bevy::transform::components::Transform;
8use serde::{Deserialize, Serialize};
9
10use crate::Transform2D;
11
12#[derive(Debug, Clone, Copy, Default, PartialEq, Reflect, Serialize, Deserialize)]
16#[serde(transparent)]
17pub struct Anchor(Vec2);
18
19impl Anchor {
20 pub const INHERIT: Self = Self(Vec2::NAN);
21 pub const BOTTOM_LEFT: Self = Self(Vec2::new(-0.5, -0.5));
22 pub const BOTTOM_CENTER: Self = Self(Vec2::new(0.0, -0.5));
23 pub const BOTTOM_RIGHT: Self = Self(Vec2::new(0.5, -0.5));
24 pub const CENTER_LEFT: Self = Self(Vec2::new(-0.5, 0.0));
25 pub const CENTER: Self = Self(Vec2::ZERO);
26 pub const CENTER_RIGHT: Self = Self(Vec2::new(0.5, 0.0));
27 pub const TOP_LEFT: Self = Self(Vec2::new(-0.5, 0.5));
28 pub const TOP_CENTER: Self = Self(Vec2::new(0.0, 0.5));
29 pub const TOP_RIGHT: Self = Self(Vec2::new(0.5, 0.5));
30
31 pub const fn new(v: Vec2) -> Self {
32 Self(v)
33 }
34
35 pub const fn custom(x: f32, y: f32) -> Self {
36 Self(Vec2::new(x, y))
37 }
38
39 pub fn is_inherit(&self) -> bool {
40 self.0.x.is_nan()
41 }
42
43 pub const fn as_vec(&self) -> Vec2 {
44 self.0
45 }
46
47 pub fn as_unit(&self) -> Vec2 {
48 self.0 + Vec2::new(0.5, 0.5)
49 }
50
51 pub const fn x(&self) -> f32 {
52 self.0.x
53 }
54
55 pub const fn y(&self) -> f32 {
56 self.0.y
57 }
58
59 pub fn or(self, other: Self) -> Self {
60 if self.is_inherit() {
61 other
62 } else {
63 self
64 }
65 }
66
67 pub fn str_name(&self) -> &'static str {
68 match (self.0.x, self.0.y) {
69 x if x.0.is_nan() || x.1.is_nan() => "Inherit",
70 (x, y) if x < -0.16 && y < -0.16 => "BottomLeft",
71 (x, y) if x < -0.16 && y > 0.16 => "TopLeft",
72 (x, _) if x < -0.16 => "CenterLeft",
73 (x, y) if x > 0.16 && y < -0.16 => "BottomRight",
74 (x, y) if x > 0.16 && y > 0.16 => "TopRight",
75 (x, _) if x > 0.16 => "CenterRight",
76 (_, y) if y < -0.16 => "BottomCenter",
77 (_, y) if y > 0.16 => "TopCenter",
78 _ => "Center",
79 }
80 }
81}
82
83impl Neg for Anchor {
84 type Output = Anchor;
85
86 fn neg(self) -> Self::Output {
87 Self(-self.0)
88 }
89}
90
91impl Mul<Vec2> for Anchor {
92 type Output = Vec2;
93
94 fn mul(self, rhs: Vec2) -> Self::Output {
95 self.0 * rhs
96 }
97}
98
99impl Mul<Anchor> for Vec2 {
100 type Output = Vec2;
101
102 fn mul(self, rhs: Anchor) -> Self::Output {
103 self * rhs.0
104 }
105}
106
107impl From<Anchor> for Vec2 {
108 fn from(val: Anchor) -> Self {
109 val.0
110 }
111}
112
113impl From<Vec2> for Anchor {
114 fn from(val: Vec2) -> Self {
115 Anchor(val)
116 }
117}
118
119#[derive(Debug, Clone, Copy, Component, PartialEq, Default, Serialize, Deserialize, Reflect)]
123#[reflect(Component, Default, Serialize, Deserialize)]
124pub struct RotatedRect {
125 pub center: Vec2,
127 pub dimension: Vec2,
129 pub rotation: f32,
131 pub z: f32,
133 pub scale: Vec2,
135 #[serde(skip)]
136 pub frame_entity: Option<Entity>,
138}
139
140#[doc(hidden)]
142#[derive(Debug, Copy, Clone)]
143pub struct ParentInfo {
144 pub dimension: Vec2,
145 pub center: Vec2,
146 pub anchor: Option<Vec2>,
147 pub affine: Transform2,
148 pub frame: Entity,
149 pub frame_rect: Rect,
150}
151
152#[doc(hidden)]
153#[derive(Debug, Copy, Clone)]
154pub struct Transform2 {
155 pub translation: Vec2,
156 pub rotation: f32,
157 pub scale: Vec2,
158}
159
160impl Transform2 {
161 pub const IDENTITY: Transform2 = Transform2 {
162 translation: Vec2::ZERO,
163 rotation: 0.,
164 scale: Vec2::ONE,
165 };
166
167 pub fn mul(&self, other: Transform2) -> Self {
168 Transform2 {
169 translation: self.transform_point2(other.translation),
170 rotation: self.rotation + other.rotation,
171 scale: self.scale * other.scale,
172 }
173 }
174
175 pub fn transform_point2(&self, point: Vec2) -> Vec2 {
176 Vec2::from_angle(self.rotation).rotate(point) * self.scale + self.translation
177 }
178}
179
180impl ParentInfo {
181 pub fn with_anchor(mut self, anc: Vec2) -> Self {
182 self.anchor = Some(anc);
183 self
184 }
185}
186
187impl RotatedRect {
188 #[inline]
190 pub fn anchor(&self, anchor: Anchor) -> Vec2 {
191 Vec2::from_angle(self.rotation).rotate(self.dimension * anchor) + self.center
192 }
193
194 #[inline]
196 pub fn half_dim(&self) -> Vec2 {
197 self.dimension / 2.
198 }
199
200 #[inline]
202 pub fn local_space(&self, position: Vec2) -> Vec2 {
203 Vec2::from_angle(-self.rotation).rotate(position - self.center)
204 }
205
206 pub(crate) fn transform2_at(&self, center: Vec2) -> Transform2 {
207 Transform2 {
208 translation: self.anchor((-center).into()),
209 rotation: self.rotation,
210 scale: self.scale,
211 }
212 }
213
214 pub fn transform_at(&self, center: Vec2) -> Transform {
215 Transform {
216 translation: self.anchor((-center).into()).extend(self.z),
217 rotation: Quat::from_rotation_z(self.rotation),
218 scale: self.scale.extend(1.0),
219 }
220 }
221
222 pub(crate) fn under_transform2(mut self, transform: Transform2) -> Self {
223 self.center = transform.transform_point2(self.center);
224 self.rotation += transform.rotation;
225 self.scale *= transform.scale;
226 self
227 }
228
229 #[inline]
231 pub fn construct(
232 parent: &ParentInfo,
233 transform: &Transform2D,
234 dimension: Vec2,
235 frame: Entity,
236 ) -> Self {
237 let parent_anchor = parent.anchor.unwrap_or(transform.get_parent_anchor());
238 let anchor = transform.anchor.as_vec();
239 Self::construct2(parent, transform, parent_anchor, anchor, dimension, frame)
240 }
241
242 #[inline]
244 #[doc(hidden)]
245 pub fn construct2(
246 parent: &ParentInfo,
247 transform: &Transform2D,
248 parent_anchor: Vec2,
249 anchor: Vec2,
250 dimension: Vec2,
251 frame: Entity,
252 ) -> Self {
253 let root = parent.dimension * parent_anchor;
254 let self_center = root + transform.offset + (transform.get_center() - anchor) * dimension;
256 Self {
257 center: self_center,
258 dimension,
259 z: transform.z,
260 rotation: transform.rotation,
261 scale: transform.scale,
262 frame_entity: Some(frame),
263 }
264 }
265
266 pub fn aabb(&self) -> Rect {
268 let bl = self.anchor(Anchor::BOTTOM_LEFT);
269 let tr = self.center * 2.0 - bl;
270 Rect {
271 min: bl.min(tr),
272 max: bl.max(tr),
273 }
274 }
275
276 pub fn is_inside(&self, rect: Rect) -> bool {
278 let bl = self.anchor(Anchor::BOTTOM_LEFT);
279 let tr = self.center * 2.0 - bl;
280 rect.contains(bl) && rect.contains(tr)
281 }
282
283 pub fn nudge_inside(&mut self, bounds: Rect) {
286 let aabb = self.aabb();
287 if aabb.size().cmpgt(bounds.size()).any() {
288 return;
289 }
290 nudge_aabb_with(&mut self.center, aabb, bounds);
291 }
292
293 pub(crate) fn nudge_inside_ext(&self, bounds: Rect, value: &mut Vec2) {
296 let aabb = self.aabb();
297 if aabb.size().cmpgt(bounds.size()).any() {
298 return;
299 }
300 nudge_aabb_with(value, aabb, bounds);
301 }
302}
303
304fn nudge_aabb_with(output: &mut Vec2, aabb: Rect, bounds: Rect) {
305 if aabb.min.x < bounds.min.x {
306 output.x += bounds.min.x - aabb.min.x;
307 } else if aabb.max.x > bounds.max.x {
308 output.x -= aabb.max.x - bounds.max.x;
309 }
310
311 if aabb.min.y < bounds.min.y {
312 output.y += bounds.min.y - aabb.min.y;
313 } else if aabb.max.y > bounds.max.y {
314 output.y -= aabb.max.y - bounds.max.y;
315 }
316}