comparison examples/stdrenderer.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, TessSliceIndex}; 8 use luminance::tess::{Mode, TessBuilder, TessSliceIndex};
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::{AnmRunner, Sprite, Vertex as FakeVertex}; 14 use touhou::th06::anm0_vm::{AnmRunner, Sprite, Vertex as FakeVertex};
15 use touhou::th06::std::{Stage, Position, Box2D}; 15 use touhou::th06::std::{Stage, Position, Box2D};
16 use touhou::th06::std_vm::StageRunner; 16 use touhou::th06::std_vm::StageRunner;
17 use touhou::util::prng::Prng; 17 use touhou::util::prng::Prng;
18 use touhou::util::math::perspective; 18 use touhou::util::math::perspective;
19 use std::cell::RefCell; 19 use std::cell::RefCell;
20 use std::fs::File;
21 use std::io::{BufReader, Read};
22 use std::rc::Rc; 20 use std::rc::Rc;
23 use std::env; 21 use std::env;
24 use std::path::Path; 22 use std::path::Path;
23
24 #[path = "common.rs"]
25 mod common;
26 use common::{load_file_into_vec, load_anm_image, LoadedTexture};
25 27
26 const VS: &str = r#" 28 const VS: &str = r#"
27 in ivec3 in_position; 29 in ivec3 in_position;
28 in vec2 in_texcoord; 30 in vec2 in_texcoord;
29 in uvec4 in_color; 31 in uvec4 in_color;
105 107
106 #[uniform(name = "fog_color")] 108 #[uniform(name = "fog_color")]
107 fog_color: Uniform<[f32; 4]>, 109 fog_color: Uniform<[f32; 4]>,
108 } 110 }
109 111
110 fn load_file_into_vec(filename: &str) -> Vec<u8> {
111 let file = File::open(filename).unwrap();
112 let mut file = BufReader::new(file);
113 let mut buf = vec![];
114 file.read_to_end(&mut buf).unwrap();
115 buf
116 }
117
118 fn main() { 112 fn main() {
119 // Parse arguments. 113 // Parse arguments.
120 let args: Vec<_> = env::args().collect(); 114 let args: Vec<_> = env::args().collect();
121 if args.len() != 4 { 115 if args.len() != 3 {
122 eprintln!("Usage: {} <STD file> <ANM file> <PNG file>", args[0]); 116 eprintln!("Usage: {} <STD file> <ANM file>", args[0]);
123 return; 117 return;
124 } 118 }
125 let std_filename = &args[1]; 119 let std_filename = Path::new(&args[1]);
126 let anm_filename = &args[2]; 120 let anm_filename = Path::new(&args[2]);
127 let png_filename = &args[3];
128 121
129 // Open the STD file. 122 // Open the STD file.
130 let buf = load_file_into_vec(std_filename); 123 let buf = load_file_into_vec(std_filename);
131 let (_, stage) = Stage::from_slice(&buf).unwrap(); 124 let (_, stage) = Stage::from_slice(&buf).unwrap();
132 125
166 let mut stage_runner = StageRunner::new(Rc::new(RefCell::new(stage))); 159 let mut stage_runner = StageRunner::new(Rc::new(RefCell::new(stage)));
167 160
168 let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap(); 161 let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap();
169 162
170 // Open the image atlas matching this ANM. 163 // Open the image atlas matching this ANM.
171 let tex = load_from_disk(&mut surface, Path::new(png_filename)).expect("texture loading"); 164 let tex = load_anm_image(&mut surface, &anm0, anm_filename);
172 165
173 // set the uniform interface to our type so that we can read textures from the shader 166 // set the uniform interface to our type so that we can read textures from the shader
174 let (program, _) = 167 let (program, _) =
175 Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS).expect("program creation"); 168 Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS).expect("program creation");
176 169
205 // and use it in the shader 198 // and use it in the shader
206 surface 199 surface
207 .pipeline_builder() 200 .pipeline_builder()
208 .pipeline(&back_buffer, [0., 0., 0., 0.], |pipeline, shd_gate| { 201 .pipeline(&back_buffer, [0., 0., 0., 0.], |pipeline, shd_gate| {
209 // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader 202 // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader
210 let bound_tex = pipeline.bind_texture(&tex); 203 let bound_tex = match &tex {
204 LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex),
205 LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex),
206 };
211 207
212 shd_gate.shade(&program, |rdr_gate, iface| { 208 shd_gate.shade(&program, |rdr_gate, iface| {
213 // update the texture; strictly speaking, this update doesn’t do much: it just tells the GPU 209 // update the texture; strictly speaking, this update doesn’t do much: it just tells the GPU
214 // to use the texture passed as argument (no allocation or copy is performed) 210 // to use the texture passed as argument (no allocation or copy is performed)
215 iface.color_map.update(&bound_tex); 211 iface.color_map.update(&bound_tex);
224 let far = stage_runner.fog_far - 101010101. / 2010101.; 220 let far = stage_runner.fog_far - 101010101. / 2010101.;
225 iface.fog_color.update(stage_runner.fog_color); 221 iface.fog_color.update(stage_runner.fog_color);
226 iface.fog_scale.update(1. / (far - near)); 222 iface.fog_scale.update(1. / (far - near));
227 iface.fog_end.update(far); 223 iface.fog_end.update(far);
228 224
225 let render_state = RenderState::default()
226 .set_blending((Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement));
227
229 let stage = stage_runner.stage.borrow(); 228 let stage = stage_runner.stage.borrow();
230 for instance in stage.instances.iter() { 229 for instance in stage.instances.iter() {
231 iface.instance_position.update([instance.pos.x, instance.pos.y, instance.pos.z]); 230 iface.instance_position.update([instance.pos.x, instance.pos.y, instance.pos.z]);
232 231
233 rdr_gate.render(RenderState::default(), |tess_gate| { 232 rdr_gate.render(render_state, |tess_gate| {
234 let (begin, end) = indices[instance.id as usize]; 233 let (begin, end) = indices[instance.id as usize];
235 tess_gate.render(&mut surface, tess.slice(begin..end)); 234 tess_gate.render(&mut surface, tess.slice(begin..end));
236 }); 235 });
237 } 236 }
238 }); 237 });
245 fn fill_vertices(sprite: Rc<RefCell<Sprite>>, vertices: &mut [Vertex; 6], x: f32, y: f32, z: f32) { 244 fn fill_vertices(sprite: Rc<RefCell<Sprite>>, vertices: &mut [Vertex; 6], x: f32, y: f32, z: f32) {
246 let mut fake_vertices = unsafe { std::mem::transmute::<&mut [Vertex; 6], &mut [FakeVertex; 4]>(vertices) }; 245 let mut fake_vertices = unsafe { std::mem::transmute::<&mut [Vertex; 6], &mut [FakeVertex; 4]>(vertices) };
247 let sprite = sprite.borrow(); 246 let sprite = sprite.borrow();
248 sprite.fill_vertices(&mut fake_vertices, x, y, z); 247 sprite.fill_vertices(&mut fake_vertices, x, y, z);
249 } 248 }
250
251 fn load_from_disk(surface: &mut GlfwSurface, path: &Path) -> Option<Texture<Flat, Dim2, NormRGB8UI>> {
252 // load the texture into memory as a whole bloc (i.e. no streaming)
253 match image::open(&path) {
254 Ok(img) => {
255 let (width, height) = img.dimensions();
256 let texels = img
257 .pixels()
258 .map(|(_x, _y, rgb)| (rgb[0], rgb[1], rgb[2]))
259 .collect::<Vec<_>>();
260
261 // create the luminance texture; the third argument is the number of mipmaps we want (leave it
262 // to 0 for now) and the latest is a the sampler to use when sampling the texels in the
263 // shader (we’ll just use the default one)
264 let tex =
265 Texture::new(surface, [width, height], 0, &Sampler::default()).expect("luminance texture creation");
266
267 // the first argument disables mipmap generation (we don’t care so far)
268 tex.upload(GenMipmaps::No, &texels);
269
270 Some(tex)
271 }
272
273 Err(e) => {
274 eprintln!("cannot open image {}: {}", path.display(), e);
275 None
276 }
277 }
278 }