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 } |