Mercurial > touhou
comparison runners/src/common.rs @ 757:21b186be2590
Split the Rust version into multiple crates.
| author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
|---|---|
| date | Tue, 05 Jan 2021 02:16:32 +0100 |
| parents | examples/common.rs@a662dddd4a2b |
| children |
comparison
equal
deleted
inserted
replaced
| 756:4d91790cf8ab | 757:21b186be2590 |
|---|---|
| 1 use image::{GenericImageView, DynamicImage, GrayImage, ImageError}; | |
| 2 use luminance::pixel::{NormRGB8UI, NormRGBA8UI}; | |
| 3 use luminance::texture::{Dim2, Dim2Array, Sampler, Texture, GenMipmaps}; | |
| 4 use luminance_glfw::GlfwSurface; | |
| 5 use touhou_formats::th06::anm0::Anm0; | |
| 6 use std::fs::File; | |
| 7 use std::io::{self, BufReader, Read}; | |
| 8 use std::path::Path; | |
| 9 | |
| 10 pub fn load_file_into_vec<P: AsRef<Path>>(filename: P) -> io::Result<Vec<u8>> { | |
| 11 let file = File::open(filename)?; | |
| 12 let mut file = BufReader::new(file); | |
| 13 let mut buf = vec![]; | |
| 14 file.read_to_end(&mut buf)?; | |
| 15 Ok(buf) | |
| 16 } | |
| 17 | |
| 18 pub enum LoadedTexture { | |
| 19 Rgba(Texture<Dim2, NormRGBA8UI>), | |
| 20 Rgb(Texture<Dim2, NormRGB8UI>), | |
| 21 RgbaArray(Texture<Dim2Array, NormRGBA8UI>), | |
| 22 } | |
| 23 | |
| 24 #[derive(Debug)] | |
| 25 pub enum TextureLoadError { | |
| 26 CannotOpenRgb(String, ImageError), | |
| 27 CannotOpenAlpha(String, ImageError), | |
| 28 AlphaToGrayscale(String), | |
| 29 } | |
| 30 | |
| 31 fn open_rgb_png(path: &Path) -> Result<DynamicImage, TextureLoadError> { | |
| 32 // load the texture into memory as a whole bloc (i.e. no streaming) | |
| 33 image::open(&path).map_err(|e| TextureLoadError::CannotOpenRgb(path.to_str().unwrap().to_owned(), e)) | |
| 34 } | |
| 35 | |
| 36 fn open_alpha_png(path: &Path) -> Result<DynamicImage, TextureLoadError> { | |
| 37 // load the texture into memory as a whole bloc (i.e. no streaming) | |
| 38 image::open(&path).map_err(|e| TextureLoadError::CannotOpenAlpha(path.to_str().unwrap().to_owned(), e)) | |
| 39 } | |
| 40 | |
| 41 fn merge_rgb_alpha(rgb: &DynamicImage, alpha: &GrayImage) -> Vec<(u8, u8, u8, u8)> { | |
| 42 rgb | |
| 43 .pixels() | |
| 44 .zip(alpha.pixels()) | |
| 45 .map(|((_x, _y, rgb), luma)| (rgb[0], rgb[1], rgb[2], luma[0])) | |
| 46 .collect::<Vec<_>>() | |
| 47 } | |
| 48 | |
| 49 pub fn load_from_data(data: &[u8]) -> Result<DynamicImage, ImageError> { | |
| 50 image::load_from_memory(data) | |
| 51 } | |
| 52 | |
| 53 pub fn reupload_texture_from_rgb_image(tex: &mut Texture<Dim2, NormRGB8UI>, img: DynamicImage) -> Result<(), TextureLoadError> { | |
| 54 let texels = img | |
| 55 .pixels() | |
| 56 .map(|(_x, _y, rgb)| (rgb[0], rgb[1], rgb[2])) | |
| 57 .collect::<Vec<_>>(); | |
| 58 | |
| 59 // the first argument disables mipmap generation (we don’t care so far) | |
| 60 tex.upload(GenMipmaps::No, &texels).unwrap(); | |
| 61 | |
| 62 Ok(()) | |
| 63 } | |
| 64 | |
| 65 pub fn upload_texture_from_rgb_image(surface: &mut GlfwSurface, img: DynamicImage) -> Result<LoadedTexture, TextureLoadError> { | |
| 66 let (width, height) = img.dimensions(); | |
| 67 | |
| 68 // create the luminance texture; the third argument is the number of mipmaps we want (leave it | |
| 69 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the | |
| 70 // shader (we’ll just use the default one) | |
| 71 let mut tex = | |
| 72 Texture::new(surface, [width, height], 0, Sampler::default()).expect("luminance texture creation"); | |
| 73 | |
| 74 reupload_texture_from_rgb_image(&mut tex, img)?; | |
| 75 | |
| 76 Ok(LoadedTexture::Rgb(tex)) | |
| 77 } | |
| 78 | |
| 79 pub fn load_rgb_texture(surface: &mut GlfwSurface, path: &Path) -> Result<LoadedTexture, TextureLoadError> { | |
| 80 let img = open_rgb_png(&path)?; | |
| 81 upload_texture_from_rgb_image(surface, img) | |
| 82 } | |
| 83 | |
| 84 fn load_rgb_a_pngs(surface: &mut GlfwSurface, rgb: &Path, alpha: &Path) -> Result<LoadedTexture, TextureLoadError> { | |
| 85 let img = open_alpha_png(&alpha)?; | |
| 86 let alpha = match img.grayscale() { | |
| 87 DynamicImage::ImageLuma8(img) => img, | |
| 88 _ => { | |
| 89 return Err(TextureLoadError::AlphaToGrayscale(alpha.to_str().unwrap().to_owned())) | |
| 90 } | |
| 91 }; | |
| 92 let (width, height) = img.dimensions(); | |
| 93 let img = open_rgb_png(&rgb)?; | |
| 94 assert_eq!((width, height), img.dimensions()); | |
| 95 let texels = merge_rgb_alpha(&img, &alpha); | |
| 96 | |
| 97 // create the luminance texture; the third argument is the number of mipmaps we want (leave it | |
| 98 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the | |
| 99 // shader (we’ll just use the default one) | |
| 100 let tex = | |
| 101 Texture::new(surface, [width, height], 0, Sampler::default()).expect("luminance texture creation"); | |
| 102 | |
| 103 // the first argument disables mipmap generation (we don’t care so far) | |
| 104 tex.upload(GenMipmaps::No, &texels).unwrap(); | |
| 105 | |
| 106 Ok(LoadedTexture::Rgba(tex)) | |
| 107 } | |
| 108 | |
| 109 pub fn load_anm_image<P: AsRef<Path>>(mut surface: &mut GlfwSurface, anm0: &Anm0, anm_filename: P) -> Result<LoadedTexture, TextureLoadError> { | |
| 110 let anm_filename = anm_filename.as_ref(); | |
| 111 let png_filename = anm_filename.with_file_name(Path::new(&anm0.png_filename).file_name().unwrap()); | |
| 112 match anm0.alpha_filename { | |
| 113 Some(ref filename) => { | |
| 114 let alpha_filename = anm_filename.with_file_name(Path::new(filename).file_name().unwrap()); | |
| 115 load_rgb_a_pngs(&mut surface, &png_filename, &alpha_filename) | |
| 116 }, | |
| 117 None => { | |
| 118 load_rgb_texture(&mut surface, &png_filename) | |
| 119 } | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 fn load_array_texture(surface: &mut GlfwSurface, images: &[(&Path, &Path)]) -> Result<LoadedTexture, TextureLoadError> { | |
| 124 let mut decoded = vec![]; | |
| 125 let dimensions = (256, 256); | |
| 126 for (rgb, alpha) in images { | |
| 127 let img = open_alpha_png(&alpha)?; | |
| 128 assert_eq!(dimensions, img.dimensions()); | |
| 129 let alpha = match img.grayscale() { | |
| 130 DynamicImage::ImageLuma8(img) => img, | |
| 131 _ => { | |
| 132 return Err(TextureLoadError::AlphaToGrayscale(alpha.to_str().unwrap().to_owned())) | |
| 133 } | |
| 134 }; | |
| 135 let img = open_rgb_png(&rgb)?; | |
| 136 assert_eq!(dimensions, img.dimensions()); | |
| 137 let texels = merge_rgb_alpha(&img, &alpha); | |
| 138 decoded.push(texels); | |
| 139 } | |
| 140 | |
| 141 // create the luminance texture; the third argument is the number of mipmaps we want (leave it | |
| 142 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the | |
| 143 // shader (we’ll just use the default one) | |
| 144 let tex = | |
| 145 Texture::new(surface, ([dimensions.0, dimensions.1], images.len() as u32), 0, Sampler::default()).expect("luminance texture creation"); | |
| 146 | |
| 147 // the first argument disables mipmap generation (we don’t care so far) | |
| 148 tex.upload(GenMipmaps::No, &decoded.into_iter().flatten().collect::<Vec<_>>()).unwrap(); | |
| 149 | |
| 150 Ok(LoadedTexture::RgbaArray(tex)) | |
| 151 } | |
| 152 | |
| 153 pub fn load_multiple_anm_images<P: AsRef<Path>>(mut surface: &mut GlfwSurface, anms: &[Anm0], anm_filename: P) -> Result<LoadedTexture, TextureLoadError> { | |
| 154 let anm_filename = anm_filename.as_ref(); | |
| 155 let mut paths = vec![]; | |
| 156 for anm0 in anms.iter() { | |
| 157 let rgb_filename = anm_filename.with_file_name(Path::new(&anm0.png_filename).file_name().unwrap()); | |
| 158 let filename = anm0.alpha_filename.as_ref().expect("Can’t not have alpha here!"); | |
| 159 let alpha_filename = anm_filename.with_file_name(Path::new(filename).file_name().unwrap()); | |
| 160 paths.push((rgb_filename, alpha_filename)); | |
| 161 } | |
| 162 let paths: Vec<_> = paths.iter().map(|(rgb, alpha)| (rgb.as_ref(), alpha.as_ref())).collect(); | |
| 163 load_array_texture(&mut surface, paths.as_slice()) | |
| 164 } |
