comparison runners/src/bin/stdrenderer.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/stdrenderer.rs@a662dddd4a2b
children
comparison
equal deleted inserted replaced
756:4d91790cf8ab 757:21b186be2590
1 use luminance::blending::{Equation, Factor};
2 use luminance::context::GraphicsContext;
3 use luminance::pipeline::{BoundTexture, PipelineState};
4 use luminance::pixel::NormUnsigned;
5 use luminance::render_state::RenderState;
6 use luminance::shader::program::{Program, Uniform};
7 use luminance::tess::{Mode, TessBuilder, TessSliceIndex};
8 use luminance::texture::Dim2;
9 use luminance_derive::{Semantics, Vertex, UniformInterface};
10 use luminance_glfw::{Action, Key, WindowEvent, GlfwSurface, Surface, WindowDim, WindowOpt};
11 use touhou_formats::th06::anm0::Anm0;
12 use touhou_formats::th06::std::{Stage, Position, Box2D};
13 use touhou_interpreters::th06::anm0::{AnmRunner, Sprite, Vertex as FakeVertex};
14 use touhou_interpreters::th06::std::StageRunner;
15 use touhou_utils::prng::Prng;
16 use touhou_utils::math::perspective;
17 use std::cell::RefCell;
18 use std::rc::Rc;
19 use std::env;
20 use std::path::Path;
21
22 use touhou_runners::common::{load_file_into_vec, load_anm_image, LoadedTexture};
23
24 const VS: &str = r#"
25 in ivec3 in_position;
26 in vec2 in_texcoord;
27 in uvec4 in_color;
28
29 uniform mat4 mvp;
30 uniform vec3 instance_position;
31
32 out vec2 texcoord;
33 out vec4 color;
34
35 void main()
36 {
37 vec3 position = vec3(in_position) + instance_position;
38 gl_Position = mvp * vec4(position, 1.0);
39 texcoord = vec2(in_texcoord);
40
41 // Normalized from the u8 being passed.
42 color = vec4(in_color) / 255.;
43 }
44 "#;
45
46 const FS: &str = r#"
47 in vec2 texcoord;
48 in vec4 color;
49
50 uniform sampler2D color_map;
51 uniform float fog_scale;
52 uniform float fog_end;
53 uniform vec4 fog_color;
54
55 out vec4 frag_color;
56
57 void main()
58 {
59 vec4 temp_color = texture(color_map, texcoord) * color;
60 float depth = gl_FragCoord.z / gl_FragCoord.w;
61 float fog_density = clamp((fog_end - depth) * fog_scale, 0.0, 1.0);
62 frag_color = vec4(mix(fog_color, temp_color, fog_density).rgb, temp_color.a);
63 }
64 "#;
65
66 #[derive(Clone, Copy, Debug, Eq, PartialEq, Semantics)]
67 pub enum Semantics {
68 #[sem(name = "in_position", repr = "[i16; 3]", wrapper = "VertexPosition")]
69 Position,
70
71 #[sem(name = "in_texcoord", repr = "[f32; 2]", wrapper = "VertexTexcoord")]
72 Texcoord,
73
74 #[sem(name = "in_color", repr = "[u8; 4]", wrapper = "VertexColor")]
75 Color,
76 }
77
78 #[repr(C)]
79 #[derive(Clone, Copy, Debug, PartialEq, Vertex)]
80 #[vertex(sem = "Semantics")]
81 struct Vertex {
82 pos: VertexPosition,
83 uv: VertexTexcoord,
84 rgba: VertexColor,
85 }
86
87 #[derive(UniformInterface)]
88 struct ShaderInterface {
89 // the 'static lifetime acts as “anything” here
90 color_map: Uniform<&'static BoundTexture<'static, Dim2, NormUnsigned>>,
91
92 #[uniform(name = "mvp")]
93 mvp: Uniform<[[f32; 4]; 4]>,
94
95 #[uniform(name = "instance_position")]
96 instance_position: Uniform<[f32; 3]>,
97
98 #[uniform(name = "fog_scale")]
99 fog_scale: Uniform<f32>,
100
101 #[uniform(name = "fog_end")]
102 fog_end: Uniform<f32>,
103
104 #[uniform(name = "fog_color")]
105 fog_color: Uniform<[f32; 4]>,
106 }
107
108 fn main() {
109 // Parse arguments.
110 let args: Vec<_> = env::args().collect();
111 if args.len() != 3 {
112 eprintln!("Usage: {} <STD file> <ANM file>", args[0]);
113 return;
114 }
115 let std_filename = Path::new(&args[1]);
116 let anm_filename = Path::new(&args[2]);
117
118 // Open the STD file.
119 let buf = load_file_into_vec(std_filename).unwrap();
120 let (_, stage) = Stage::from_slice(&buf).unwrap();
121
122 // Open the ANM file.
123 let buf = load_file_into_vec(anm_filename).unwrap();
124 let (_, mut anms) = Anm0::from_slice(&buf).unwrap();
125 let anm0 = anms.pop().unwrap();
126
127 // TODO: seed this PRNG with a valid seed.
128 let prng = Rc::new(RefCell::new(Prng::new(0)));
129
130 let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap();
131
132 // Open the image atlas matching this ANM.
133 let tex = load_anm_image(&mut surface, &anm0, anm_filename).expect("image loading");
134
135 assert_eq!(std::mem::size_of::<Vertex>(), std::mem::size_of::<FakeVertex>());
136 let mut vertices: Vec<Vertex> = vec![];
137 let mut indices = vec![];
138
139 {
140 let anms = Rc::new(RefCell::new([anm0]));
141 for model in stage.models.iter() {
142 let begin = vertices.len();
143 for quad in model.quads.iter() {
144 let Position { x, y, z } = quad.pos;
145 let Box2D { width, height } = quad.size_override;
146
147 // Create the AnmRunner from the ANM and the sprite.
148 let sprite = Rc::new(RefCell::new(Sprite::with_size(width, height)));
149 let _anm_runner = AnmRunner::new(anms.clone(), quad.anm_script as u8, sprite.clone(), Rc::downgrade(&prng), 0);
150 let mut new_vertices: [Vertex; 6] = {
151 let data = std::mem::MaybeUninit::uninit();
152 unsafe { data.assume_init() }
153 };
154 fill_vertices(sprite.clone(), &mut new_vertices, x, y, z);
155 new_vertices[4] = new_vertices[0];
156 new_vertices[5] = new_vertices[2];
157 vertices.extend(&new_vertices);
158 }
159 let end = vertices.len();
160 indices.push((begin, end));
161 }
162 }
163
164 let mut stage_runner = StageRunner::new(Rc::new(RefCell::new(stage)));
165
166 // set the uniform interface to our type so that we can read textures from the shader
167 let program =
168 Program::<Semantics, (), ShaderInterface>::from_strings(None, VS, None, FS).expect("program creation").ignore_warnings();
169
170 let tess = TessBuilder::new(&mut surface)
171 .add_vertices(vertices)
172 .set_mode(Mode::Triangle)
173 .build()
174 .unwrap();
175
176 let mut back_buffer = surface.back_buffer().unwrap();
177 let mut resize = false;
178
179 'app: loop {
180 for event in surface.poll_events() {
181 match event {
182 WindowEvent::Close | WindowEvent::Key(Key::Escape, _, Action::Release, _) => break 'app,
183
184 WindowEvent::FramebufferSize(..) => {
185 resize = true;
186 }
187
188 _ => (),
189 }
190 }
191
192 if resize {
193 back_buffer = surface.back_buffer().unwrap();
194 resize = false;
195 }
196
197 {
198 stage_runner.run_frame();
199 //let sprites = stage.get_sprites();
200 //fill_vertices_ptr(sprites, slice.as_mut_ptr());
201 }
202
203 // here, we need to bind the pipeline variable; it will enable us to bind the texture to the GPU
204 // and use it in the shader
205 surface
206 .pipeline_builder()
207 .pipeline(&back_buffer, &PipelineState::default(), |pipeline, mut shd_gate| {
208 // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader
209 let bound_tex = match &tex {
210 LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex),
211 LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex),
212 LoadedTexture::RgbaArray(tex) => unreachable!(),
213 };
214
215 shd_gate.shade(&program, |iface, mut rdr_gate| {
216 // update the texture; strictly speaking, this update doesn’t do much: it just tells the GPU
217 // to use the texture passed as argument (no allocation or copy is performed)
218 iface.color_map.update(&bound_tex);
219
220 let proj = perspective(0.5235987755982988, 384. / 448., 101010101./2010101., 101010101./10101.);
221 let model_view = stage_runner.get_model_view();
222 let mvp = model_view * proj;
223 // TODO: check how to pass by reference.
224 iface.mvp.update(*mvp.borrow_inner());
225
226 let near = stage_runner.fog_near - 101010101. / 2010101.;
227 let far = stage_runner.fog_far - 101010101. / 2010101.;
228 iface.fog_color.update(stage_runner.fog_color);
229 iface.fog_scale.update(1. / (far - near));
230 iface.fog_end.update(far);
231
232 let render_state = RenderState::default()
233 .set_blending((Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement));
234
235 let stage = stage_runner.stage.borrow();
236 for instance in stage.instances.iter() {
237 iface.instance_position.update([instance.pos.x, instance.pos.y, instance.pos.z]);
238
239 rdr_gate.render(&render_state, |mut tess_gate| {
240 let (begin, end) = indices[instance.id as usize];
241 tess_gate.render(tess.slice(begin..end));
242 });
243 }
244 });
245 });
246
247 surface.swap_buffers();
248 }
249 }
250
251 fn fill_vertices(sprite: Rc<RefCell<Sprite>>, vertices: &mut [Vertex; 6], x: f32, y: f32, z: f32) {
252 let mut fake_vertices = unsafe { std::mem::transmute::<&mut [Vertex; 6], &mut [FakeVertex; 4]>(vertices) };
253 let sprite = sprite.borrow();
254 sprite.fill_vertices(&mut fake_vertices, x, y, z);
255 }