1use std::ops::Range;
2
3use bevy::prelude::{Bundle, Color, Component, IVec2, Image, Transform};
4
5use crate::TILE_SIZE;
6
7#[derive(Component)]
8pub struct DeletingTile;
9
10#[derive(Bundle)]
11pub struct TileBundle {
12 transform: Transform,
13 tile: Tile,
14}
15
16impl TileBundle {
17 pub fn new(tile: Tile, location: IVec2) -> Self {
18 Self {
19 tile,
20 transform: Transform::from_xyz(location.x as f32, location.y as f32, 0.0),
21 }
22 }
23}
24
25#[derive(Component, Debug, Clone, PartialEq)]
26pub struct Tile {
27 pub(crate) pixels: [[Color; TILE_SIZE]; TILE_SIZE],
28}
29
30impl Tile {
31 pub fn from_color(color: Color) -> Self {
32 Self {
33 pixels: [[color; TILE_SIZE]; TILE_SIZE],
34 }
35 }
36
37 pub fn from_pixels(pixels: [[Color; TILE_SIZE]; TILE_SIZE]) -> Self {
38 Self { pixels }
39 }
40
41 pub fn from_image(image: &Image, pixel_range: (Range<usize>, Range<usize>)) -> Self {
42 let mut colors = [[Color::NONE; TILE_SIZE]; TILE_SIZE];
43
44 assert_eq!(pixel_range.0.len(), TILE_SIZE);
45 assert_eq!(pixel_range.1.len(), TILE_SIZE);
46
47 for x in pixel_range.0.clone() {
48 for y in pixel_range.1.clone() {
49 let pixel_index = y * image.size().x as usize * 4 + x * 4;
50
51 colors[y - pixel_range.1.start][x - pixel_range.0.start] = Color::rgba_u8(
52 image.data[pixel_index],
53 image.data[pixel_index + 1],
54 image.data[pixel_index + 2],
55 image.data[pixel_index + 3],
56 );
57 }
58 }
59
60 Self { pixels: colors }
61 }
62
63 pub fn set_pixel(&mut self, loc: IVec2, color: Color) {
64 if !verify_pixel_loc(loc) {
65 return;
66 }
67
68 self.pixels[loc.y as usize][loc.x as usize] = color
69 }
70
71 pub fn get_pixel(&self, loc: IVec2) -> Option<Color> {
72 if !verify_pixel_loc(loc) {
73 return None;
74 }
75
76 Some(self.pixels[loc.y as usize][loc.x as usize])
77 }
78
79 pub fn pixel_count(&self) -> usize {
80 let mut pixel_count = 0;
81 for x in 0..TILE_SIZE {
82 for y in 0..TILE_SIZE {
83 if self.pixels[y][x].a() > 0.0 {
84 pixel_count += 1;
85 }
86 }
87 }
88
89 pixel_count
90 }
91}
92
93fn verify_pixel_loc(loc: IVec2) -> bool {
94 if loc.x < 0 || loc.x >= TILE_SIZE as i32 || loc.y < 0 || loc.y >= TILE_SIZE as i32 {
95 return false;
96 }
97 true
98}