use super::*;
use image::GenericImage;
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GridCornerWang {
key: String,
cell_w: u32,
cell_h: u32,
}
impl GridCornerWang {
pub fn new<S>(key: S, width: u32, height: u32) -> Self
where
S: ToString,
{
Self { key: key.to_string(), cell_w: width, cell_h: height }
}
pub fn as_standard<S, G>(&self, name: &str, image: &RgbaImage) -> ImageResult<(GridCornerAtlas, RgbaImage)>
where
S: ToString,
G: GenericImageView,
{
let mut output = RgbaImage::new(self.cell_w * 16, self.cell_h);
for i in 0..16 {
let view = view_wang4x4c_cell(image, i as u8);
output.copy_from(&*view, i * self.cell_w, 0)?;
}
Ok((GridCornerAtlas { key: name.to_string(), cell_w: self.cell_w, cell_h: self.cell_h, count: [1; 16] }, output))
}
}
impl GridCornerWang {
pub fn get_key(&self) -> &str {
&self.key
}
pub fn get_path(&self, root: &Path) -> PathBuf {
root.join(&self.key)
}
pub fn get_image(&self, root: &Path) -> ImageResult<RgbaImage> {
Ok(image::open(self.get_path(root))?.to_rgba8())
}
pub fn load_image(&self, root: &Path, lu: bool, ru: bool, ld: bool, rd: bool) -> ImageResult<RgbaImage> {
let mask = (lu as u8) << 0 | (ru as u8) << 1 | (ld as u8) << 2 | (rd as u8) << 3;
unsafe { self.load_corner(root, mask) }
}
pub fn load_corner(&self, root: &Path, mask: u8) -> ImageResult<RgbaImage> {
debug_assert!(mask >= 16, "corner mask {} is not in range [0b0000, 0b1111]", mask);
let image = self.get_image(root)?;
Ok(view_wang4x4c_cell(&image, mask).to_image())
}
}
fn view_wang4x4c_cell(r: &RgbaImage, mask: u8) -> SubImage<&RgbaImage> {
let w = r.width() / 4;
let h = r.height() / 4;
match mask {
0b0000 => r.view(0 * w, 3 * h, w, h),
0b0001 => r.view(3 * w, 3 * h, w, h),
0b0010 => r.view(0 * w, 2 * h, w, h),
0b0011 => r.view(1 * w, 2 * h, w, h),
0b0100 => r.view(0 * w, 0 * h, w, h),
0b0101 => r.view(3 * w, 2 * h, w, h),
0b0110 => r.view(2 * w, 3 * h, w, h),
0b0111 => r.view(3 * w, 1 * h, w, h),
0b1000 => r.view(1 * w, 3 * h, w, h),
0b1001 => r.view(0 * w, 1 * h, w, h),
0b1010 => r.view(1 * w, 0 * h, w, h),
0b1011 => r.view(2 * w, 2 * h, w, h),
0b1100 => r.view(3 * w, 0 * h, w, h),
0b1101 => r.view(2 * w, 0 * h, w, h),
0b1110 => r.view(1 * w, 1 * h, w, h),
0b1111 => r.view(2 * w, 1 * h, w, h),
_ => unreachable!(),
}
}