comparison examples/anmrenderer.rs @ 705:ed65f9412bc0

anmrenderer: split common loading functions in another module.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 23 Aug 2019 19:29:00 +0200
parents 84af5bedbde4
children bca515da9047
comparison
equal deleted inserted replaced
704:84af5bedbde4 705:ed65f9412bc0
1 use image::{GenericImageView, DynamicImage};
2 use luminance::blending::{Equation, Factor}; 1 use luminance::blending::{Equation, Factor};
3 use luminance::context::GraphicsContext; 2 use luminance::context::GraphicsContext;
4 use luminance::framebuffer::Framebuffer; 3 use luminance::framebuffer::Framebuffer;
5 use luminance::pipeline::BoundTexture; 4 use luminance::pipeline::BoundTexture;
6 use luminance::pixel::{NormRGB8UI, NormRGBA8UI, Floating}; 5 use luminance::pixel::Floating;
7 use luminance::render_state::RenderState; 6 use luminance::render_state::RenderState;
8 use luminance::shader::program::{Program, Uniform}; 7 use luminance::shader::program::{Program, Uniform};
9 use luminance::tess::{Mode, TessBuilder}; 8 use luminance::tess::{Mode, TessBuilder};
10 use luminance::texture::{Dim2, Flat, Sampler, Texture, GenMipmaps}; 9 use luminance::texture::{Dim2, Flat};
11 use luminance_derive::{Semantics, Vertex, UniformInterface}; 10 use luminance_derive::{Semantics, Vertex, UniformInterface};
12 use luminance_glfw::event::{Action, Key, WindowEvent}; 11 use luminance_glfw::event::{Action, Key, WindowEvent};
13 use luminance_glfw::surface::{GlfwSurface, Surface, WindowDim, WindowOpt}; 12 use luminance_glfw::surface::{GlfwSurface, Surface, WindowDim, WindowOpt};
14 use touhou::th06::anm0::Anm0; 13 use touhou::th06::anm0::Anm0;
15 use touhou::th06::anm0_vm::{AnmRunner, Sprite, Vertex as FakeVertex}; 14 use touhou::th06::anm0_vm::{AnmRunner, Sprite, Vertex as FakeVertex};
16 use touhou::util::math::{perspective, setup_camera}; 15 use touhou::util::math::{perspective, setup_camera};
17 use touhou::util::prng::Prng; 16 use touhou::util::prng::Prng;
18 use std::cell::RefCell; 17 use std::cell::RefCell;
19 use std::fs::File;
20 use std::io::{BufReader, Read};
21 use std::rc::Rc; 18 use std::rc::Rc;
22 use std::env; 19 use std::env;
23 use std::path::Path; 20 use std::path::Path;
21
22 #[path = "common.rs"]
23 mod common;
24
25 use common::{load_file_into_vec, load_rgb_png, load_rgb_a_pngs, LoadedTexture};
24 26
25 const VS: &str = r#" 27 const VS: &str = r#"
26 in ivec3 in_position; 28 in ivec3 in_position;
27 in vec2 in_texcoord; 29 in vec2 in_texcoord;
28 in vec4 in_color; 30 in vec4 in_color;
85 87
86 #[uniform(name = "mvp")] 88 #[uniform(name = "mvp")]
87 mvp: Uniform<[[f32; 4]; 4]>, 89 mvp: Uniform<[[f32; 4]; 4]>,
88 } 90 }
89 91
90 fn load_file_into_vec(filename: &Path) -> Vec<u8> { 92 fn fill_vertices_ptr(sprite: Rc<RefCell<Sprite>>, vertices: *mut Vertex) {
91 let file = File::open(filename).unwrap(); 93 let mut fake_vertices = unsafe { std::mem::transmute::<*mut Vertex, &mut [FakeVertex; 4]>(vertices) };
92 let mut file = BufReader::new(file); 94 sprite.borrow().fill_vertices(&mut fake_vertices, 0., 0., 0.);
93 let mut buf = vec![]; 95 }
94 file.read_to_end(&mut buf).unwrap(); 96
95 buf 97 fn fill_vertices(sprite: Rc<RefCell<Sprite>>, vertices: &mut [Vertex; 4]) {
96 } 98 let mut fake_vertices = unsafe { std::mem::transmute::<&mut [Vertex; 4], &mut [FakeVertex; 4]>(vertices) };
97 99 sprite.borrow().fill_vertices(&mut fake_vertices, 0., 0., 0.);
98 enum LoadedTexture {
99 Rgba(Texture<Flat, Dim2, NormRGBA8UI>),
100 Rgb(Texture<Flat, Dim2, NormRGB8UI>),
101 } 100 }
102 101
103 fn main() { 102 fn main() {
104 // Parse arguments. 103 // Parse arguments.
105 let args: Vec<_> = env::args().collect(); 104 let args: Vec<_> = env::args().collect();
138 // Open the image atlas matching this ANM. 137 // Open the image atlas matching this ANM.
139 let png_filename = anm_filename.with_file_name(Path::new(&anm0.png_filename).file_name().unwrap()); 138 let png_filename = anm_filename.with_file_name(Path::new(&anm0.png_filename).file_name().unwrap());
140 let tex = match anm0.alpha_filename { 139 let tex = match anm0.alpha_filename {
141 Some(ref filename) => { 140 Some(ref filename) => {
142 let alpha_filename = anm_filename.with_file_name(Path::new(filename).file_name().unwrap()); 141 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")) 142 load_rgb_a_pngs(&mut surface, &png_filename, &alpha_filename).expect("texture loading")
144 }, 143 },
145 None => { 144 None => {
146 LoadedTexture::Rgb(load_from_disk(&mut surface, &png_filename).expect("texture loading")) 145 load_rgb_png(&mut surface, &png_filename).expect("texture loading")
147 } 146 }
148 }; 147 };
149 148
150 // set the uniform interface to our type so that we can read textures from the shader 149 // set the uniform interface to our type so that we can read textures from the shader
151 let (program, _) = 150 let (program, _) =
216 }); 215 });
217 216
218 surface.swap_buffers(); 217 surface.swap_buffers();
219 } 218 }
220 } 219 }
221
222 fn fill_vertices_ptr(sprite: Rc<RefCell<Sprite>>, vertices: *mut Vertex) {
223 let mut fake_vertices = unsafe { std::mem::transmute::<*mut Vertex, &mut [FakeVertex; 4]>(vertices) };
224 sprite.borrow().fill_vertices(&mut fake_vertices, 0., 0., 0.);
225 }
226
227 fn fill_vertices(sprite: Rc<RefCell<Sprite>>, vertices: &mut [Vertex; 4]) {
228 let mut fake_vertices = unsafe { std::mem::transmute::<&mut [Vertex; 4], &mut [FakeVertex; 4]>(vertices) };
229 sprite.borrow().fill_vertices(&mut fake_vertices, 0., 0., 0.);
230 }
231
232 fn load_from_disk(surface: &mut GlfwSurface, path: &Path) -> Option<Texture<Flat, Dim2, NormRGB8UI>> {
233 // load the texture into memory as a whole bloc (i.e. no streaming)
234 match image::open(&path) {
235 Ok(img) => {
236 let (width, height) = img.dimensions();
237 let texels = img
238 .pixels()
239 .map(|(_x, _y, rgb)| (rgb[0], rgb[1], rgb[2]))
240 .collect::<Vec<_>>();
241
242 // create the luminance texture; the third argument is the number of mipmaps we want (leave it
243 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the
244 // shader (we’ll just use the default one)
245 let tex =
246 Texture::new(surface, [width, height], 0, &Sampler::default()).expect("luminance texture creation");
247
248 // the first argument disables mipmap generation (we don’t care so far)
249 tex.upload(GenMipmaps::No, &texels);
250
251 Some(tex)
252 }
253
254 Err(e) => {
255 eprintln!("cannot open image {}: {}", path.display(), e);
256 None
257 }
258 }
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 }