1use std;
43use derive_more::{From, TryInto};
44use lazy_static::lazy_static;
45
46use crate::math::Vector2;
49use crate::geometry::integer::Aabb2;
50
51pub use self::position::Position;
52pub use self::dimensions::Dimensions;
53
54lazy_static!{
55 pub (crate) static ref TILE_WH : [u32; 2] = {
56 let width = std::env::var ("GOOEY_TILE_WIDTH").unwrap().parse().unwrap();
57 let height = std::env::var ("GOOEY_TILE_HEIGHT").unwrap().parse().unwrap();
58 [width, height]
59 };
60 pub (crate) static ref SCREEN_WH : std::sync::RwLock <[u32; 2]> =
61 std::sync::RwLock::new ([0, 0]);
62}
63
64#[derive(Clone, Copy, Debug, Eq, PartialEq, From, TryInto)]
65pub enum Coordinates {
66 Tile (position::Tile, dimensions::Tile),
67 Pixel (position::Pixel, dimensions::Pixel)
68}
69
70#[derive(Clone, Copy, Debug, Eq, PartialEq)]
71pub enum Kind {
72 Tile, Pixel
73}
74
75pub fn pixel_to_tile (x : i32, y : i32) -> [i32; 2] {
77 let [tile_w, tile_h] = *TILE_WH;
78 let [_screen_w, screen_h] = *SCREEN_WH.read().unwrap();
79 let column = x / tile_w as i32;
80 let row = (screen_h as i32 - y) / tile_h as i32;
81 [row, column]
82}
83
84pub fn pixel_to_tile_aabb (aabb : Aabb2 <i32>) -> Aabb2 <i32> {
86 let [min_x, min_y] = aabb.min().0.into_array();
87 let [max_x, max_y] = aabb.max().0.into_array();
88 let min = pixel_to_tile (min_x, max_y).into();
89 let max = pixel_to_tile (max_x, min_y).into();
90 Aabb2::with_minmax (min, max)
91}
92
93pub fn tile_to_pixel (row : i32, column : i32) -> [i32; 2] {
95 let [tile_w, tile_h] = *TILE_WH;
96 let [_screen_w, screen_h] = *SCREEN_WH.read().unwrap();
97 let x = column * tile_w as i32;
98 let y = screen_h as i32 - row * tile_h as i32;
99 [x, y]
100}
101
102pub fn tile_to_pixel_aabb (aabb : Aabb2 <i32>) -> Aabb2 <i32> {
104 let aabb = Aabb2::with_minmax (
105 *aabb.min(),
106 aabb.max() + Vector2::new (1, 1)
107 );
108 let [min_row, min_col] = aabb.min().0.into_array();
109 let [max_row, max_col] = aabb.max().0.into_array();
110 let min = tile_to_pixel (max_row, min_col).into();
111 let max = tile_to_pixel (min_row, max_col).into();
112 Aabb2::with_minmax (min, max)
113}
114
115impl Coordinates {
116 #[inline]
117 pub fn default_tile() -> Self {
118 (position::Tile::default(), dimensions::Tile::default()).into()
119 }
120 #[inline]
121 pub fn default_pixel() -> Self {
122 (position::Pixel::default(), dimensions::Pixel::default()).into()
123 }
124 pub fn tile_from_aabb (aabb : Aabb2 <i32>) -> Self {
125 let position = (*aabb.min()).into();
126 let dimensions = ((*aabb.max() - aabb.min()) + Vector2::new (1, 1))
127 .numcast().unwrap().into();
128 Coordinates::Tile (position, dimensions)
129 }
130 pub fn pixel_from_aabb (aabb : Aabb2 <i32>) -> Self {
131 let position = (*aabb.min()).into();
132 let dimensions = ((*aabb.max() - aabb.min()) + Vector2::new (1, 1))
133 .numcast().unwrap().into();
134 Coordinates::Pixel (position, dimensions)
135 }
136 #[inline]
137 pub fn kind (&self) -> Kind {
138 match self {
139 Coordinates::Tile (_, _) => Kind::Tile,
140 Coordinates::Pixel (_, _) => Kind::Pixel
141 }
142 }
143 #[inline]
144 pub fn dimensions (&self) -> Dimensions {
145 match self {
146 Coordinates::Tile (_, dimensions) => dimensions.clone().into(),
147 Coordinates::Pixel (_, dimensions) => dimensions.clone().into()
148 }
149 }
150 #[inline]
151 pub fn position (&self) -> Position {
152 match self {
153 Coordinates::Tile (position, _) => position.clone().into(),
154 Coordinates::Pixel (position, _) => position.clone().into()
155 }
156 }
157 #[inline]
158 pub fn dimensions_horizontal (&self) -> u32 {
159 match self {
160 Coordinates::Tile (_, dimensions) => dimensions.columns(),
161 Coordinates::Pixel (_, dimensions) => dimensions.width()
162 }
163 }
164 #[inline]
165 pub fn dimensions_vertical (&self) -> u32 {
166 match self {
167 Coordinates::Tile (_, dimensions) => dimensions.rows(),
168 Coordinates::Pixel (_, dimensions) => dimensions.height()
169 }
170 }
171 #[inline]
172 pub fn position_horizontal (&self) -> i32 {
173 match self {
174 Coordinates::Tile (position, _) => position.column(),
175 Coordinates::Pixel (position, _) => position.0.x
176 }
177 }
178 #[inline]
179 pub fn position_vertical (&self) -> i32 {
180 match self {
181 Coordinates::Tile (position, _) => position.row(),
182 Coordinates::Pixel (position, _) => position.0.y
183 }
184 }
185 #[inline]
186 pub fn modify_dimensions_horizontal (&mut self, d : i32) {
187 match self {
188 Coordinates::Tile (_, dimensions) =>
189 *dimensions.columns_mut() =
190 std::cmp::max (0, dimensions.columns() as i32 + d) as u32,
191 Coordinates::Pixel (_, dimensions) =>
192 dimensions.x = std::cmp::max (0, dimensions.x as i32 + d) as u32
193 }
194 }
195 #[inline]
196 pub fn modify_dimensions_vertical (&mut self, d : i32) {
197 match self {
198 Coordinates::Tile (_, dimensions) =>
199 *dimensions.rows_mut() =
200 std::cmp::max (0, dimensions.rows() as i32 + d) as u32,
201 Coordinates::Pixel (_, dimensions) =>
202 dimensions.y = std::cmp::max (0, dimensions.y as i32 + d) as u32
203 }
204 }
205 #[inline]
206 pub fn modify_position_horizontal (&mut self, d : i32) {
207 match self {
208 Coordinates::Tile (position, _) =>
209 *position.column_mut() = position.column() + d,
210 Coordinates::Pixel (position, _) => position.0.x = position.0.x + d
211 }
212 }
213 #[inline]
214 pub fn modify_position_vertical (&mut self, d : i32) {
215 match self {
216 Coordinates::Tile (position, _) =>
217 *position.row_mut() = position.row() + d,
218 Coordinates::Pixel (position, _) => position.0.y = position.0.y + d
219 }
220 }
221 #[inline]
222 pub fn set_position (&mut self, position : Position) {
224 match (self, position) {
225 (Coordinates::Tile (position, _), Position::Tile (p)) => *position = p,
226 (Coordinates::Pixel (position, _), Position::Pixel (p)) => *position = p,
227 _ => unreachable!()
228 }
229 }
230 #[inline]
231 pub fn set_dimensions (&mut self, dimensions : Dimensions) {
233 match (self, dimensions) {
234 (Coordinates::Tile (_, dimensions), Dimensions::Tile (d)) =>
235 *dimensions = d,
236 (Coordinates::Pixel (_, dimensions), Dimensions::Pixel (d)) =>
237 *dimensions = d,
238 _ => unreachable!()
239 }
240 }
241}
242
243impl From <Coordinates> for Aabb2 <i32> {
244 fn from (coordinates : Coordinates) -> Aabb2 <i32> {
245 log::trace!("aabb2 from coordinates: {:?}", coordinates);
246 let (min, max) = match coordinates {
250 Coordinates::Tile (position, dimensions) => {
251 let mut max = *position + dimensions.numcast().unwrap();
252 if dimensions.x > 0 {
253 max.0.x -= 1;
254 }
255 if dimensions.y > 0 {
256 max.0.y -= 1;
257 }
258 (*position, max)
259 }
260 Coordinates::Pixel (position, dimensions) => {
261 let mut max = *position + dimensions.numcast().unwrap();
262 if dimensions.x > 0 {
263 max.0.x -= 1;
264 }
265 if dimensions.y > 0 {
266 max.0.y -= 1;
267 }
268 (*position, max)
269 }
270 };
271 log::trace!("aabb2 with min, max: {:?}", (min, max));
272 Aabb2::with_minmax (min, max)
273 }
274}
275
276impl std::convert::TryFrom <(Position, Dimensions)> for Coordinates {
277 type Error = (Position, Dimensions);
278 fn try_from ((position, dimensions) : (Position, Dimensions))
279 -> Result <Coordinates, (Position, Dimensions)>
280 {
281 let coordinates = match (position, dimensions) {
282 (Position::Tile (position), Dimensions::Tile (dimensions)) =>
283 Coordinates::Tile (position, dimensions),
284 (Position::Pixel (position), Dimensions::Pixel (dimensions)) =>
285 Coordinates::Pixel (position, dimensions),
286 _ => return Err ((position, dimensions))
287 };
288 Ok (coordinates)
289 }
290}
291
292pub mod position {
293 use derive_more::{From, TryInto};
294 use crate::math::Point2;
295
296 #[derive(Clone, Copy, Debug, Eq, PartialEq, From, TryInto)]
297 pub enum Position {
298 Tile (Tile),
299 Pixel (Pixel)
300 }
301
302 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
303 pub struct Tile {
304 pub position_rc : Point2 <i32>
305 }
306
307 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
308 pub struct Pixel {
309 pub position_xy : Point2 <i32>
310 }
311
312 impl Tile {
315 #[inline]
316 pub const fn origin() -> Self {
317 Tile {
318 position_rc: Point2::new (0, 0)
319 }
320 }
321 #[inline]
322 pub fn new_rc (row : i32, column : i32) -> Self {
323 Point2::new (row, column).into()
324 }
325 #[inline]
326 pub fn row (&self) -> i32 {
327 self.position_rc.0.x
328 }
329 #[inline]
330 pub fn column (&self) -> i32 {
331 self.position_rc.0.y
332 }
333 #[inline]
334 pub fn row_mut (&mut self) -> &mut i32 {
335 &mut self.position_rc.0.x
336 }
337 #[inline]
338 pub fn column_mut (&mut self) -> &mut i32 {
339 &mut self.position_rc.0.y
340 }
341 }
342
343 impl Default for Tile {
344 fn default() -> Self {
345 Tile { position_rc: [0,0].into() }
346 }
347 }
348
349 impl From <Point2 <i32>> for Tile {
350 fn from (position_rc : Point2 <i32>) -> Self {
351 Tile { position_rc }
352 }
353 }
354
355 impl std::ops::Deref for Tile {
356 type Target = Point2 <i32>;
357 fn deref (&self) -> &Point2 <i32> {
358 &self.position_rc
359 }
360 }
361
362 impl std::ops::DerefMut for Tile {
363 fn deref_mut (&mut self) -> &mut Point2 <i32> {
364 &mut self.position_rc
365 }
366 }
367
368 impl Pixel {
369 #[inline]
370 pub const fn origin() -> Self {
371 Pixel {
372 position_xy: Point2::new (0, 0)
373 }
374 }
375 #[inline]
376 pub fn new_xy (x : i32, y : i32) -> Self {
377 Point2::new (x, y).into()
378 }
379 }
380
381 impl Default for Pixel {
382 fn default() -> Self {
383 Pixel { position_xy: [0,0].into() }
384 }
385 }
386
387 impl From <Point2 <i32>> for Pixel {
388 fn from (position_xy : Point2 <i32>) -> Self {
389 Pixel { position_xy }
390 }
391 }
392
393 impl std::ops::Deref for Pixel {
394 type Target = Point2 <i32>;
395 fn deref (&self) -> &Point2 <i32> {
396 &self.position_xy
397 }
398 }
399
400 impl std::ops::DerefMut for Pixel {
401 fn deref_mut (&mut self) -> &mut Point2 <i32> {
402 &mut self.position_xy
403 }
404 }
405}
406
407pub mod dimensions {
408 use derive_more::{From, TryInto};
409 use crate::math::Vector2;
410
411 #[derive(Clone, Copy, Debug, Eq, PartialEq, From, TryInto)]
412 pub enum Dimensions {
413 Tile (Tile),
414 Pixel (Pixel)
415 }
416
417 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
418 pub struct Tile {
419 pub dimensions_rc : Vector2 <u32>
420 }
421
422 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
423 pub struct Pixel {
424 pub dimensions_xy : Vector2 <u32>
425 }
426
427 impl Dimensions {
430 pub fn horizontal (&self) -> u32 {
431 match self {
432 Dimensions::Tile (tile) => tile.columns(),
433 Dimensions::Pixel (pixel) => pixel.width()
434 }
435 }
436
437 pub fn vertical (&self) -> u32 {
438 match self {
439 Dimensions::Tile (tile) => tile.rows(),
440 Dimensions::Pixel (pixel) => pixel.height()
441 }
442 }
443
444 pub fn vec (&self) -> Vector2 <u32> {
445 match self {
446 Dimensions::Tile (tile) => **tile,
447 Dimensions::Pixel (pixel) => **pixel
448 }
449 }
450 }
451
452 impl Tile {
453 #[inline]
454 pub fn new_rc (rows : u32, columns : u32) -> Self {
455 Vector2::new (rows, columns).into()
456 }
457 #[inline]
458 pub fn columns (&self) -> u32 {
459 self.dimensions_rc.y
460 }
461 #[inline]
462 pub fn rows (&self) -> u32 {
463 self.dimensions_rc.x
464 }
465 #[inline]
466 pub fn rows_mut (&mut self) -> &mut u32 {
467 &mut self.dimensions_rc.x
468 }
469 #[inline]
470 pub fn columns_mut (&mut self) -> &mut u32 {
471 &mut self.dimensions_rc.y
472 }
473 #[inline]
474 pub fn to_pixel (self) -> Pixel {
475 Vector2::new (self.columns(), self.rows()).into()
476 }
477 }
478
479 impl Pixel {
480 #[inline]
481 pub fn new_wh (width : u32, height : u32) -> Self {
482 Vector2::new (width, height).into()
483 }
484 #[inline]
485 pub fn width (&self) -> u32 {
486 self.dimensions_xy.x
487 }
488 #[inline]
489 pub fn height (&self) -> u32 {
490 self.dimensions_xy.y
491 }
492 #[inline]
493 pub fn to_tile (self) -> Tile {
494 Vector2::new (self.height(), self.width()).into()
495 }
496 }
497
498 impl Default for Tile {
499 fn default() -> Self {
500 Tile { dimensions_rc: [0,0].into() }
501 }
502 }
503
504 impl From <Vector2 <u32>> for Tile {
505 fn from (dimensions_rc : Vector2 <u32>) -> Self {
506 Tile { dimensions_rc }
507 }
508 }
509
510 impl std::ops::Deref for Tile {
511 type Target = Vector2 <u32>;
512 fn deref (&self) -> &Self::Target {
513 &self.dimensions_rc
514 }
515 }
516
517 impl std::ops::DerefMut for Tile {
518 fn deref_mut (&mut self) -> &mut Self::Target {
519 &mut self.dimensions_rc
520 }
521 }
522
523 impl Default for Pixel {
524 fn default() -> Self {
525 Pixel { dimensions_xy: [0,0].into() }
526 }
527 }
528
529 impl From <Vector2 <u32>> for Pixel {
530 fn from (dimensions_xy : Vector2 <u32>) -> Self {
531 Pixel { dimensions_xy }
532 }
533 }
534
535 impl std::ops::Deref for Pixel {
536 type Target = Vector2 <u32>;
537 fn deref (&self) -> &Self::Target {
538 &self.dimensions_xy
539 }
540 }
541
542 impl std::ops::DerefMut for Pixel {
543 fn deref_mut (&mut self) -> &mut Self::Target {
544 &mut self.dimensions_xy
545 }
546 }
547}
548
549impl std::ops::Add <dimensions::Tile> for position::Tile {
550 type Output = Self;
551 fn add (self, rhs : dimensions::Tile) -> Self {
552 (self.position_rc + rhs.dimensions_rc.numcast().unwrap()).into()
553 }
554}
555
556impl std::ops::Add <dimensions::Pixel> for position::Pixel {
557 type Output = Self;
558 fn add (self, rhs : dimensions::Pixel) -> Self {
559 (self.position_xy + rhs.dimensions_xy.numcast().unwrap()).into()
560 }
561}
562
563impl std::ops::Sub <dimensions::Tile> for position::Tile {
564 type Output = Self;
565 fn sub (self, rhs : dimensions::Tile) -> Self {
566 (self.position_rc - rhs.dimensions_rc.numcast().unwrap()).into()
567 }
568}
569
570impl std::ops::Sub <dimensions::Pixel> for position::Pixel {
571 type Output = Self;
572 fn sub (self, rhs : dimensions::Pixel) -> Self {
573 (self.position_xy - rhs.dimensions_xy.numcast().unwrap()).into()
574 }
575}
576
577#[cfg(test)]
578mod tests {
579 use crate::geometry::integer::Aabb2;
580 use super::*;
581 #[test]
603 fn test_tile_to_pixel_aabb() {
604 unsafe {
605 std::env::set_var ("GOOEY_TILE_WIDTH", "8");
606 std::env::set_var ("GOOEY_TILE_HEIGHT", "8");
607 }
608 *SCREEN_WH.write().unwrap() = [100, 100];
609 let coordinates = Coordinates::Tile (
610 position::Tile::new_rc (0, 0),
611 dimensions::Tile::new_rc (1, 1));
612 let aabb = Aabb2::from (coordinates);
613 assert!(aabb.contains (&[0, 0].into()));
614 assert!(!aabb.contains (&[1, 1].into()));
615 let aabb_pixel = tile_to_pixel_aabb (aabb);
616 assert_eq!(*aabb_pixel.min(), [0, 92].into());
617 assert_eq!(*aabb_pixel.max(), [8, 100].into());
618 }
619}