use coffee::graphics::{Canvas, Gpu, Image}; mod mesh; use mesh::Mesh; use std::fs::File; use std::io::Read; use std::path::PathBuf; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Test { Mesh, } impl Test { pub fn all() -> Vec { vec![Test::Mesh] } pub fn run(&self, gpu: &mut Gpu) -> Drawing { let draw = match self { Test::Mesh => Mesh::draw(), }; Drawing { test: *self, canvas: draw .run(gpu) .expect(&format!("Run test \"{}\"", self.to_string())), } } } impl std::string::ToString for Test { fn to_string(&self) -> String { let name = match self { Test::Mesh => "mesh", }; String::from(name) } } pub struct Drawing { test: Test, canvas: Canvas, } impl Drawing { pub fn test(&self) -> Test { self.test } pub fn canvas(&self) -> &Canvas { &self.canvas } pub fn save_as_model(&self, gpu: &mut Gpu) { let model_path = self.model_path(); let model_directory = model_path.parent().expect("Get model directory"); let image = self.canvas.read_pixels(gpu); std::fs::create_dir_all(model_directory) .expect("Create model directory"); image .to_rgba() .save(self.model_path()) .expect(&format!("Save \"{:?}\" drawing", self.test)); } pub fn differences( &self, gpu: &mut Gpu, ) -> Result, Error> { let model = { let mut buf = Vec::new(); let mut reader = File::open(self.model_path())?; let _ = reader.read_to_end(&mut buf)?; image::load_from_memory(&buf)? }; let image = self.canvas.read_pixels(gpu); let model_rgba = model.to_rgba(); let image_rgba = image.to_rgba(); if model_rgba .pixels() .zip(image_rgba.pixels()) .all(|(a, b)| a == b) { Ok(None) } else { let differences: Vec = model_rgba .pixels() .zip(image_rgba.pixels()) .flat_map(|(a, b)| { if a == b { &[0, 0, 0, 0] } else { &[255, 0, 0, 255] } }) .cloned() .collect(); let image = image::RgbaImage::from_raw( self.canvas.width() as u32, self.canvas.height() as u32, differences, ) .expect("Create diff image"); let image = Image::from_image(gpu, &image::DynamicImage::ImageRgba8(image)) .expect("Upload diff image"); Ok(Some(Differences { test: self.test, canvas: self.canvas.clone(), image, })) } } fn model_path(&self) -> PathBuf { let mut path = PathBuf::new(); path.push("tests"); path.push("_graphics"); path.push("models"); path.push(self.test.to_string()); path.set_extension("png"); path } } #[derive(Debug)] pub struct Differences { test: Test, canvas: Canvas, image: Image, } impl Differences { pub fn test(&self) -> Test { self.test } pub fn canvas(&self) -> &Canvas { &self.canvas } pub fn image(&self) -> &Image { &self.image } } #[derive(Debug)] pub enum Error { ModelImageNotFound(std::io::Error), ModelImageIsInvalid(image::ImageError), } impl From for Error { fn from(error: std::io::Error) -> Error { Error::ModelImageNotFound(error) } } impl From for Error { fn from(error: image::ImageError) -> Error { Error::ModelImageIsInvalid(error) } }