comparison examples/eclrenderer.rs @ 706:bca515da9047

examples: use common module.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 23 Aug 2019 19:46:47 +0200
parents b6c351ca0a35
children 987409d48991
comparison
equal deleted inserted replaced
705:ed65f9412bc0 706:bca515da9047
1 use image::GenericImageView; 1 use luminance::blending::{Equation, Factor};
2 use luminance::context::GraphicsContext; 2 use luminance::context::GraphicsContext;
3 use luminance::framebuffer::Framebuffer; 3 use luminance::framebuffer::Framebuffer;
4 use luminance::pipeline::BoundTexture; 4 use luminance::pipeline::BoundTexture;
5 use luminance::pixel::{NormRGB8UI, Floating}; 5 use luminance::pixel::Floating;
6 use luminance::render_state::RenderState; 6 use luminance::render_state::RenderState;
7 use luminance::shader::program::{Program, Uniform}; 7 use luminance::shader::program::{Program, Uniform};
8 use luminance::tess::{Mode, TessBuilder}; 8 use luminance::tess::{Mode, TessBuilder};
9 use luminance::texture::{Dim2, Flat, Sampler, Texture, GenMipmaps}; 9 use luminance::texture::{Dim2, Flat};
10 use luminance_derive::{Semantics, Vertex, UniformInterface}; 10 use luminance_derive::{Semantics, Vertex, UniformInterface};
11 use luminance_glfw::event::{Action, Key, WindowEvent}; 11 use luminance_glfw::event::{Action, Key, WindowEvent};
12 use luminance_glfw::surface::{GlfwSurface, Surface, WindowDim, WindowOpt}; 12 use luminance_glfw::surface::{GlfwSurface, Surface, WindowDim, WindowOpt};
13 use touhou::th06::anm0::Anm0; 13 use touhou::th06::anm0::Anm0;
14 use touhou::th06::anm0_vm::{Sprite, Vertex as FakeVertex}; 14 use touhou::th06::anm0_vm::{Sprite, Vertex as FakeVertex};
16 use touhou::th06::ecl_vm::EclRunner; 16 use touhou::th06::ecl_vm::EclRunner;
17 use touhou::th06::enemy::{Enemy, Game, Position}; 17 use touhou::th06::enemy::{Enemy, Game, Position};
18 use touhou::util::math::{perspective, setup_camera}; 18 use touhou::util::math::{perspective, setup_camera};
19 use touhou::util::prng::Prng; 19 use touhou::util::prng::Prng;
20 use std::cell::RefCell; 20 use std::cell::RefCell;
21 use std::fs::File;
22 use std::io::{BufReader, Read};
23 use std::rc::Rc; 21 use std::rc::Rc;
24 use std::env; 22 use std::env;
25 use std::path::Path; 23 use std::path::Path;
24
25 #[path = "common.rs"]
26 mod common;
27 use common::{load_file_into_vec, load_anm_image, LoadedTexture};
26 28
27 const VS: &str = r#" 29 const VS: &str = r#"
28 in ivec3 in_position; 30 in ivec3 in_position;
29 in vec2 in_texcoord; 31 in vec2 in_texcoord;
30 in uvec4 in_color; 32 in uvec4 in_color;
86 88
87 #[uniform(name = "mvp")] 89 #[uniform(name = "mvp")]
88 mvp: Uniform<[[f32; 4]; 4]>, 90 mvp: Uniform<[[f32; 4]; 4]>,
89 } 91 }
90 92
91 fn load_file_into_vec(filename: &str) -> Vec<u8> {
92 let file = File::open(filename).unwrap();
93 let mut file = BufReader::new(file);
94 let mut buf = vec![];
95 file.read_to_end(&mut buf).unwrap();
96 buf
97 }
98
99 fn main() { 93 fn main() {
100 // Parse arguments. 94 // Parse arguments.
101 let args: Vec<_> = env::args().collect(); 95 let args: Vec<_> = env::args().collect();
102 if args.len() != 6 { 96 if args.len() != 5 {
103 eprintln!("Usage: {} <ECL file> <ANM file> <PNG file> <easy|normal|hard|lunatic> <sub number>", args[0]); 97 eprintln!("Usage: {} <ECL file> <ANM file> <easy|normal|hard|lunatic> <sub number>", args[0]);
104 return; 98 return;
105 } 99 }
106 let ecl_filename = &args[1]; 100 let ecl_filename = Path::new(&args[1]);
107 let anm_filename = &args[2]; 101 let anm_filename = Path::new(&args[2]);
108 let png_filename = &args[3]; 102 let rank: Rank = args[3].parse().expect("rank");
109 let rank: Rank = args[4].parse().expect("rank"); 103 let sub: u16 = args[4].parse().expect("number");
110 let sub: u16 = args[5].parse().expect("number");
111 104
112 // Open the ECL file. 105 // Open the ECL file.
113 let buf = load_file_into_vec(ecl_filename); 106 let buf = load_file_into_vec(ecl_filename);
114 let (_, ecl) = Ecl::from_slice(&buf).unwrap(); 107 let (_, ecl) = Ecl::from_slice(&buf).unwrap();
115 108
140 let vertices: [Vertex; 4] = unsafe { std::mem::uninitialized() }; 133 let vertices: [Vertex; 4] = unsafe { std::mem::uninitialized() };
141 134
142 let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap(); 135 let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap();
143 136
144 // Open the image atlas matching this ANM. 137 // Open the image atlas matching this ANM.
145 let tex = load_from_disk(&mut surface, Path::new(png_filename)).expect("texture loading"); 138 let tex = load_anm_image(&mut surface, &anm0.borrow(), anm_filename);
146 139
147 // set the uniform interface to our type so that we can read textures from the shader 140 // set the uniform interface to our type so that we can read textures from the shader
148 let (program, _) = 141 let (program, _) =
149 Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS).expect("program creation"); 142 Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS).expect("program creation");
150 143
193 // and use it in the shader 186 // and use it in the shader
194 surface 187 surface
195 .pipeline_builder() 188 .pipeline_builder()
196 .pipeline(&back_buffer, [0., 0., 0., 0.], |pipeline, shd_gate| { 189 .pipeline(&back_buffer, [0., 0., 0., 0.], |pipeline, shd_gate| {
197 // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader 190 // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader
198 let bound_tex = pipeline.bind_texture(&tex); 191 let bound_tex = match &tex {
192 LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex),
193 LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex),
194 };
199 195
200 shd_gate.shade(&program, |rdr_gate, iface| { 196 shd_gate.shade(&program, |rdr_gate, iface| {
201 // update the texture; strictly speaking, this update doesn’t do much: it just tells the GPU 197 // update the texture; strictly speaking, this update doesn’t do much: it just tells the GPU
202 // to use the texture passed as argument (no allocation or copy is performed) 198 // to use the texture passed as argument (no allocation or copy is performed)
203 iface.color_map.update(&bound_tex); 199 iface.color_map.update(&bound_tex);
207 let mvp = view * proj; 203 let mvp = view * proj;
208 //println!("{:#?}", mvp); 204 //println!("{:#?}", mvp);
209 // TODO: check how to pass by reference. 205 // TODO: check how to pass by reference.
210 iface.mvp.update(*mvp.borrow_inner()); 206 iface.mvp.update(*mvp.borrow_inner());
211 207
212 rdr_gate.render(RenderState::default(), |tess_gate| { 208 let render_state = RenderState::default()
209 .set_blending((Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement));
210
211 rdr_gate.render(render_state, |tess_gate| {
213 // render the tessellation to the surface the regular way and let the vertex shader’s 212 // render the tessellation to the surface the regular way and let the vertex shader’s
214 // magic do the rest! 213 // magic do the rest!
215 tess_gate.render(&mut surface, (&tess).into()); 214 tess_gate.render(&mut surface, (&tess).into());
216 }); 215 });
217 }); 216 });
226 for (x, y, z, sprite) in sprites { 225 for (x, y, z, sprite) in sprites {
227 let sprite = sprite.borrow(); 226 let sprite = sprite.borrow();
228 sprite.fill_vertices(&mut fake_vertices, x, y, z); 227 sprite.fill_vertices(&mut fake_vertices, x, y, z);
229 } 228 }
230 } 229 }
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 }