comparison examples/anmrenderer.rs @ 704:84af5bedbde4

anmrenderer: also load the alpha PNG.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 23 Aug 2019 19:09:37 +0200
parents b6c351ca0a35
children ed65f9412bc0
comparison
equal deleted inserted replaced
703:81232dac8136 704:84af5bedbde4
1 use image::GenericImageView; 1 use image::{GenericImageView, DynamicImage};
2 use luminance::blending::{Equation, Factor}; 2 use luminance::blending::{Equation, Factor};
3 use luminance::context::GraphicsContext; 3 use luminance::context::GraphicsContext;
4 use luminance::framebuffer::Framebuffer; 4 use luminance::framebuffer::Framebuffer;
5 use luminance::pipeline::BoundTexture; 5 use luminance::pipeline::BoundTexture;
6 use luminance::pixel::{NormRGB8UI, Floating}; 6 use luminance::pixel::{NormRGB8UI, NormRGBA8UI, Floating};
7 use luminance::render_state::RenderState; 7 use luminance::render_state::RenderState;
8 use luminance::shader::program::{Program, Uniform}; 8 use luminance::shader::program::{Program, Uniform};
9 use luminance::tess::{Mode, TessBuilder}; 9 use luminance::tess::{Mode, TessBuilder};
10 use luminance::texture::{Dim2, Flat, Sampler, Texture, GenMipmaps}; 10 use luminance::texture::{Dim2, Flat, Sampler, Texture, GenMipmaps};
11 use luminance_derive::{Semantics, Vertex, UniformInterface}; 11 use luminance_derive::{Semantics, Vertex, UniformInterface};
85 85
86 #[uniform(name = "mvp")] 86 #[uniform(name = "mvp")]
87 mvp: Uniform<[[f32; 4]; 4]>, 87 mvp: Uniform<[[f32; 4]; 4]>,
88 } 88 }
89 89
90 fn load_file_into_vec(filename: &str) -> Vec<u8> { 90 fn load_file_into_vec(filename: &Path) -> Vec<u8> {
91 let file = File::open(filename).unwrap(); 91 let file = File::open(filename).unwrap();
92 let mut file = BufReader::new(file); 92 let mut file = BufReader::new(file);
93 let mut buf = vec![]; 93 let mut buf = vec![];
94 file.read_to_end(&mut buf).unwrap(); 94 file.read_to_end(&mut buf).unwrap();
95 buf 95 buf
96 } 96 }
97 97
98 enum LoadedTexture {
99 Rgba(Texture<Flat, Dim2, NormRGBA8UI>),
100 Rgb(Texture<Flat, Dim2, NormRGB8UI>),
101 }
102
98 fn main() { 103 fn main() {
99 // Parse arguments. 104 // Parse arguments.
100 let args: Vec<_> = env::args().collect(); 105 let args: Vec<_> = env::args().collect();
101 if args.len() != 4 { 106 if args.len() != 3 {
102 eprintln!("Usage: {} <ANM file> <PNG file> <script number>", args[0]); 107 eprintln!("Usage: {} <ANM file> <script number>", args[0]);
103 return; 108 return;
104 } 109 }
105 let anm_filename = &args[1]; 110 let anm_filename = Path::new(&args[1]);
106 let png_filename = &args[2]; 111 let script: u8 = args[2].parse().expect("number");
107 let script: u8 = args[3].parse().expect("number");
108 112
109 // Open the ANM file. 113 // Open the ANM file.
110 let buf = load_file_into_vec(anm_filename); 114 let buf = load_file_into_vec(anm_filename);
111 let (_, mut anms) = Anm0::from_slice(&buf).unwrap(); 115 let (_, mut anms) = Anm0::from_slice(&buf).unwrap();
112 let anm0 = anms.pop().unwrap(); 116 let anm0 = anms.pop().unwrap();
130 fill_vertices(sprite.clone(), &mut vertices); 134 fill_vertices(sprite.clone(), &mut vertices);
131 135
132 let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap(); 136 let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap();
133 137
134 // Open the image atlas matching this ANM. 138 // Open the image atlas matching this ANM.
135 println!("{} {}", anm0.first_name, png_filename); 139 let png_filename = anm_filename.with_file_name(Path::new(&anm0.png_filename).file_name().unwrap());
136 let tex = load_from_disk(&mut surface, Path::new(png_filename)).expect("texture loading"); 140 let tex = match anm0.alpha_filename {
141 Some(ref filename) => {
142 let alpha_filename = anm_filename.with_file_name(Path::new(filename).file_name().unwrap());
143 LoadedTexture::Rgba(png_alpha(&mut surface, &png_filename, &alpha_filename).expect("texture loading"))
144 },
145 None => {
146 LoadedTexture::Rgb(load_from_disk(&mut surface, &png_filename).expect("texture loading"))
147 }
148 };
137 149
138 // set the uniform interface to our type so that we can read textures from the shader 150 // set the uniform interface to our type so that we can read textures from the shader
139 let (program, _) = 151 let (program, _) =
140 Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS).expect("program creation"); 152 Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS).expect("program creation");
141 153
173 // and use it in the shader 185 // and use it in the shader
174 surface 186 surface
175 .pipeline_builder() 187 .pipeline_builder()
176 .pipeline(&back_buffer, [0., 0., 0., 0.], |pipeline, shd_gate| { 188 .pipeline(&back_buffer, [0., 0., 0., 0.], |pipeline, shd_gate| {
177 // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader 189 // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader
178 let bound_tex = pipeline.bind_texture(&tex); 190 let bound_tex = match &tex {
191 LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex),
192 LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex),
193 };
179 194
180 shd_gate.shade(&program, |rdr_gate, iface| { 195 shd_gate.shade(&program, |rdr_gate, iface| {
181 // update the texture; strictly speaking, this update doesn’t do much: it just tells the GPU 196 // update the texture; strictly speaking, this update doesn’t do much: it just tells the GPU
182 // to use the texture passed as argument (no allocation or copy is performed) 197 // to use the texture passed as argument (no allocation or copy is performed)
183 iface.color_map.update(&bound_tex); 198 iface.color_map.update(&bound_tex);
219 match image::open(&path) { 234 match image::open(&path) {
220 Ok(img) => { 235 Ok(img) => {
221 let (width, height) = img.dimensions(); 236 let (width, height) = img.dimensions();
222 let texels = img 237 let texels = img
223 .pixels() 238 .pixels()
224 .map(|(x, y, rgb)| (rgb[0], rgb[1], rgb[2])) 239 .map(|(_x, _y, rgb)| (rgb[0], rgb[1], rgb[2]))
225 .collect::<Vec<_>>(); 240 .collect::<Vec<_>>();
226 241
227 // create the luminance texture; the third argument is the number of mipmaps we want (leave it 242 // create the luminance texture; the third argument is the number of mipmaps we want (leave it
228 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the 243 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the
229 // shader (we’ll just use the default one) 244 // shader (we’ll just use the default one)
240 eprintln!("cannot open image {}: {}", path.display(), e); 255 eprintln!("cannot open image {}: {}", path.display(), e);
241 None 256 None
242 } 257 }
243 } 258 }
244 } 259 }
260
261 fn png_alpha(surface: &mut GlfwSurface, rgb: &Path, alpha: &Path) -> Option<Texture<Flat, Dim2, NormRGBA8UI>> {
262 // load the texture into memory as a whole bloc (i.e. no streaming)
263 match image::open(&alpha) {
264 Ok(img) => {
265 let (width, height) = img.dimensions();
266 let alpha = match img.grayscale() {
267 DynamicImage::ImageLuma8(img) => img,
268 _ => {
269 eprintln!("cannot convert alpha image {} to grayscale", alpha.display());
270 return None;
271 }
272 };
273 let img = match image::open(&rgb) {
274 Ok(img) => img,
275 Err(e) => {
276 eprintln!("cannot open rgb image {}: {}", rgb.display(), e);
277 return None;
278 },
279 };
280 let texels = img
281 .pixels()
282 .zip(alpha.pixels())
283 .map(|((_x, _y, rgb), luma)| (rgb[0], rgb[1], rgb[1], luma[0]))
284 .collect::<Vec<_>>();
285
286 // create the luminance texture; the third argument is the number of mipmaps we want (leave it
287 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the
288 // shader (we’ll just use the default one)
289 let tex =
290 Texture::new(surface, [width, height], 0, &Sampler::default()).expect("luminance texture creation");
291
292 // the first argument disables mipmap generation (we don’t care so far)
293 tex.upload(GenMipmaps::No, &texels);
294
295 Some(tex)
296 }
297
298 Err(e) => {
299 eprintln!("cannot open alpha image {}: {}", alpha.display(), e);
300 None
301 }
302 }
303 }