From 3024c5dfb352a3f9011a5ce9aa50fe7dc1a2e013 Mon Sep 17 00:00:00 2001 From: Bernie Innocenti Date: Sun, 12 Jan 2020 04:52:35 +0900 Subject: [PATCH] Cleanly separate rendering and event handling Moving to glium 0.26 / glutin 0.22 required adopting a new event loop stlye, which in turn was the right excuse for a long overdue code rework. Some things still don't work quite right at this point, FPS computation is incorrect and some keyboard commands are still commented out... But hey, the code looks much nicer now! --- Cargo.toml | 4 +- bounding_box.rs | 11 +- lib.rs | 2 + main.rs | 434 ++++++++++++++++++++++++++-------------------- release_wasm.sh | 3 +- rust-rocket | 2 +- shaded_cube.rs | 11 +- support/camera.rs | 11 +- text.rs | 14 +- 9 files changed, 275 insertions(+), 217 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 42244c2..3ee753a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ opt-level = 3 [dependencies] cgmath = "*" #gleam = "*" -glium = "0.25.1" -glutin = "0.21" +glium = "0.26.0-alpha6" +glutin = "0.22.0-alpha6" image = { version = "*", features = ["png_codec"], optional = true } libxm = "1.0.0" rust-rocket = { path = "rust-rocket", optional = true } diff --git a/bounding_box.rs b/bounding_box.rs index 71cee76..6625eb5 100644 --- a/bounding_box.rs +++ b/bounding_box.rs @@ -2,6 +2,7 @@ use crate::cube::Cube; use glium; use glium::{Display, Program, Surface, implement_vertex}; use glium::index::{IndexBuffer, PrimitiveType}; +use std::rc::Rc; pub fn solid_fill_program(display: &Display) -> Program { let vertex_shader_src = include_str!("shaders/solid.vert"); @@ -13,14 +14,14 @@ pub fn solid_fill_program(display: &Display) -> Program { struct Vertex { position: [f32; 3] } implement_vertex!(Vertex, position); -pub struct BoundingBox<'a> { +pub struct BoundingBox { vertexes: glium::VertexBuffer, - program: &'a Program, + program: Rc, indices: IndexBuffer, } -impl<'a> BoundingBox<'a> { - pub fn new(display: &Display, c: &Cube, program: &'a Program) -> BoundingBox<'a> { +impl BoundingBox { + pub fn new(display: &Display, c: &Cube, program: Rc) -> BoundingBox { let vertex_data = [ Vertex { position: [c.xmin, c.ymin, c.zmin] }, Vertex { position: [c.xmax, c.ymin, c.zmin] }, @@ -54,6 +55,6 @@ impl<'a> BoundingBox<'a> { blend: glium::Blend::alpha_blending(), ..Default::default() }; - frame.draw(&self.vertexes, &self.indices, self.program, uniforms, ¶ms).unwrap(); + frame.draw(&self.vertexes, &self.indices, &self.program, uniforms, ¶ms).unwrap(); } } diff --git a/lib.rs b/lib.rs index 25e275c..24ef697 100644 --- a/lib.rs +++ b/lib.rs @@ -10,6 +10,8 @@ pub mod timer; pub use crate::bounding_box::BoundingBox; pub use crate::cube::Cube; pub use crate::shaded_cube::ShadedCube; +pub use crate::text::Text; +pub use crate::timer::Timer; #[cfg(feature = "image")] pub fn screenshot(display : &glium::Display) { diff --git a/main.rs b/main.rs index 1ad2eea..86a17c2 100644 --- a/main.rs +++ b/main.rs @@ -1,11 +1,12 @@ use cgmath::conv::array4x4; use cgmath::{Euler, Matrix4, Rad, SquareMatrix, Vector3, Vector4, Zero}; -use glium::glutin::VirtualKeyCode; -use glium::glutin::WindowEvent::KeyboardInput; -use glium::{Surface, uniform}; +use glium::glutin::event::{ self, Event, VirtualKeyCode, WindowEvent }; +use glium::glutin::event_loop::{ ControlFlow }; +use glium::{Display, Program, Surface, uniform}; use mandelwow_lib::*; use std::f32::consts::PI; -use crate::timer::Timer; +use std::rc::Rc; +use std::time::{Duration, Instant}; #[cfg(target_os = "emscripten")] use std::os::raw::{c_int, c_void}; @@ -25,6 +26,170 @@ fn gl_info(display: &glium::Display) { } } +const SEA_XSIZE: usize = 40; +const SEA_ZSIZE: usize = 25; + +struct World<'a> { + display: Display, + + mandelwow_program: Rc, + mandelwow_bounds: Cube, + mandelwow_bbox: BoundingBox, + bounding_box_enabled: bool, + + shaded_cube: ShadedCube, + text: Text<'a>, + + sea: [[Vector3; SEA_ZSIZE]; SEA_XSIZE], + + // For the zoom animation synchronized to the drum-hits + hit_time: f32, + last_hit: f32, +} + +impl<'a> World<'a> { + pub fn new(display: glium::Display) -> World<'a> { + let mandelwow_program = Rc::new(mandelwow::program(&display)); + let bounding_box_program = Rc::new(bounding_box::solid_fill_program(&display)); + let shaded_program = Rc::new(shaded_cube::shaded_program(&display)); + + // These are the bounds for the 3D slice of the 4D Mandelwow + let mandelwow_bounds = Cube { + xmin: -2.0, + xmax: 0.7, + ymin: -1.0, + ymax: 1.0, + zmin: -1.1, + zmax: 1.1, + }; + + // Generate a wavy sea made of cubes + let sea_xmin = -20.0f32; + let sea_xmax = 20.0f32; + let sea_y = -2.5; + let sea_zmin = -2.0f32; + let sea_zmax = -27.0f32; + let sea_xstep = (sea_xmax - sea_xmin) / (SEA_XSIZE as f32); + let sea_zstep = (sea_zmax - sea_zmin) / (SEA_ZSIZE as f32); + println!("xstep={} ystep={:?}", sea_xstep, sea_zstep); + + let mut sea = [[Vector3::zero(); SEA_ZSIZE]; SEA_XSIZE]; + for x in 0..SEA_XSIZE { + for z in 0..SEA_ZSIZE { + sea[x][z] = Vector3 { + x: sea_xmin + (x as f32) * sea_xstep, + y: sea_y, + z: sea_zmin + (z as f32) * sea_zstep, + }; + } + } + + World { + mandelwow_program, + mandelwow_bbox: BoundingBox::new( + &display, &mandelwow_bounds, bounding_box_program.clone()), + mandelwow_bounds, + bounding_box_enabled: true, + + shaded_cube: ShadedCube::new(&display, shaded_program.clone()), + text: text::Text::new(&display), + sea: sea, + + hit_time: 0.0, + last_hit: 0.0, + + display, + } + } + + fn draw_frame( + &self, + camera: &support::camera::CameraState, + t: f32, + ) { + let perspview = camera.get_perspview(); + + let hit_delta = t - self.hit_time; + let hit_scale = 1. / (1. + hit_delta * hit_delta * 15.0) + 1.; + + // Vary the wow factor to slice the Mandelwow along its 4th dimension. + let wmin = -0.8; + let wmax = 0.8; + let wsize = wmax - wmin; + let wow = (((t * 0.7).sin() + 1.0) / 2.0) * wsize + wmin; + + //println!("t={} w={:?} camera={:?}", t, w, camera.get_pos()); + + let mut frame = self.display.draw(); + frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0); + + let rotation = Matrix4::from(Euler { + x: Rad(t.sin() / 3.), + y: Rad(t.sin() / 2.), + z: Rad(t / 1.5), + }); + let z_trans = -3.0; // Send the model back a little bit so it fits the screen. + let scale = Matrix4::from_diagonal(Vector4::new(hit_scale, hit_scale, hit_scale, 1.0)); + let model2 = Matrix4::from_translation(Vector3::unit_z() * z_trans) * rotation * scale; + let model = array4x4(model2); + + // Draw the bounding box before the fractal, when the Z-buffer is still clear, + // so the lines behind the semi-translucent areas will be drawn. + if self.bounding_box_enabled { + let uniforms = uniform! { + model: model, + view: camera.get_view(), + perspective: camera.get_perspective(), + }; + self.mandelwow_bbox.draw(&mut frame, &uniforms); + } + + let text_rot = Matrix4::from_angle_x(cgmath::Deg(-90.0f32)); + let text_pos = Matrix4::from_translation(Vector3 { + x: 0.0, + y: 0.501, + z: 0.0f32, + }) * text_rot; + for x in 0..SEA_XSIZE { + for z in 0..SEA_ZSIZE { + let wave = ((x as f32 / SEA_XSIZE as f32 * PI * 5.0 + t * 2.0).sin() + + (z as f32 / SEA_ZSIZE as f32 * PI * 3.0 + t * 3.0).sin()) + * 0.3; + let model = Matrix4::from_translation( + self.sea[x][z] + + Vector3 { + x: 0., + y: wave, + z: 0., + }, + ); + let uniforms = uniform! { + model: array4x4(model), + perspview: perspview, + col: [0., (1. - wave).abs() * 0.5, wave.abs()], + }; + self.shaded_cube.draw(&mut frame, &uniforms); + let model = model * text_pos; + let c = (x + z * SEA_XSIZE) as u8 as char; + self.text.draw(&mut frame, c, &model, &perspview); + } + } + + mandelwow::draw( + &self.display, + &mut frame, + &self.mandelwow_program, + model, + &camera, + &self.mandelwow_bounds, + wow, + ); + + frame.finish().unwrap(); + } +} + + #[cfg(target_os = "emscripten")] #[allow(non_camel_case_types)] type em_callback_func = unsafe extern "C" fn(); @@ -71,11 +236,13 @@ where //extern crate gleam; +/* extern "C" { fn emscripten_GetProcAddress( name: *const ::std::os::raw::c_char, ) -> *const ::std::os::raw::c_void; } +*/ fn main() { /* @@ -88,218 +255,107 @@ fn main() { let mut soundplayer = sound::start(); - let mut events_loop = glium::glutin::EventsLoop::new(); - let window = glium::glutin::WindowBuilder::new() + let event_loop = glutin::event_loop::EventLoop::new(); + //let fullscreen = Some(glutin::window::Fullscreen::Borderless(event_loop.primary_monitor())); + let window = glutin::window::WindowBuilder::new() //.with_dimensions(1280, 720) - .with_fullscreen(Some(events_loop.get_primary_monitor())); + //.with_fullscreen(fullscreen); + ; //.with_title("MandelWow"); - let context = glium::glutin::ContextBuilder::new() + let context = glutin::ContextBuilder::new() //.with_gl_profile(glutin::GlProfile::Core) - //.with_gl(glium::glutin::GlRequest::Specific(glium::glutin::Api::WebGl, (2, 0))) - .with_gl(glium::glutin::GlRequest::Specific( - glium::glutin::Api::OpenGlEs, + //.with_gl(glutin::GlRequest::Specific(glutin::Api::WebGl, (2, 0))) + .with_gl(glutin::GlRequest::Specific( + glutin::Api::OpenGlEs, (3, 0), )) - //.with_gl(glium::glutin::GlRequest::Specific(glium::glutin::Api::OpenGl, (4, 0))) + //.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (4, 0))) //.with_depth_buffer(24) .with_vsync(true); - let display = glium::Display::new(window, context, &events_loop).unwrap(); - gl_info(&display); - let mut text = text::Text::new(&display, 'A'); - let mandelwow_program = mandelwow::program(&display); - let bounding_box_program = bounding_box::solid_fill_program(&display); - let shaded_program = shaded_cube::shaded_program(&display); + let display = glium::Display::new(window, context, &event_loop).unwrap(); + gl_info(&display); + let mut world = World::new(display); let mut timer = Timer::new(); let mut camera = support::camera::CameraState::new(); - let bounding_box_enabled = true; let _fullscreen = true; - // These are the bounds of the 3D Mandelwow section which we render in 3-space. - let bounds = Cube { - xmin: -2.0, - xmax: 0.7, - ymin: -1.0, - ymax: 1.0, - zmin: -1.1, - zmax: 1.1, - }; - - let mandelwow_bbox = bounding_box::BoundingBox::new(&display, &bounds, &bounding_box_program); - let shaded_cube = ShadedCube::new(&display, &shaded_program); - - const SEA_XSIZE: usize = 40; - const SEA_ZSIZE: usize = 25; - let sea_xmin = -20.0f32; - let sea_xmax = 20.0f32; - let sea_y = -2.5; - let sea_zmin = -2.0f32; - let sea_zmax = -27.0f32; - let sea_xstep = (sea_xmax - sea_xmin) / (SEA_XSIZE as f32); - let sea_zstep = (sea_zmax - sea_zmin) / (SEA_ZSIZE as f32); - println!("xstep={} ystep={:?}", sea_xstep, sea_zstep); - - let mut sea = [[Vector3::zero(); SEA_ZSIZE]; SEA_XSIZE]; - for x in 0..SEA_XSIZE { - for z in 0..SEA_ZSIZE { - sea[x][z] = Vector3 { - x: sea_xmin + (x as f32) * sea_xstep, - y: sea_y, - z: sea_zmin + (z as f32) * sea_zstep, - }; - } - } - - let mut last_hit = 0.0f32; - let mut hit_time = 0.0f32; - set_main_loop_callback(|| { + event_loop.run(move |event, _, control_flow| { let t = timer.t; let new_hit = sound::hit_event(&mut soundplayer); - if new_hit > last_hit { - hit_time = t; + if new_hit > world.last_hit { + world.hit_time = t; } - last_hit = new_hit; - let hit_delta = t - hit_time; - let hit_scale = 1. / (1. + hit_delta * hit_delta * 15.0) + 1.; + world.last_hit = new_hit; camera.update(); - let perspview = camera.get_perspview(); - - // Vary the wow factor to slice the Mandelwow along its 4th dimension. - let wmin = -0.8; - let wmax = 0.8; - let wsize = wmax - wmin; - let wow = (((t * 0.7).sin() + 1.0) / 2.0) * wsize + wmin; - - //println!("t={} w={:?} camera={:?}", t, w, camera.get_pos()); - - let mut frame = display.draw(); - frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0); - - let rotation = Matrix4::from(Euler { - x: Rad(t.sin() / 3.), - y: Rad(t.sin() / 2.), - z: Rad(t / 1.5), - }); - let z_trans = -3.0; // Send the model back a little bit so it fits the screen. - let scale = Matrix4::from_diagonal(Vector4::new(hit_scale, hit_scale, hit_scale, 1.0)); - let model2 = Matrix4::from_translation(Vector3::unit_z() * z_trans) * rotation * scale; - let model = array4x4(model2); - - // Draw the bounding box before the fractal, when the Z-buffer is still clear, - // so the lines behind the semi-translucent areas will be drawn. - if bounding_box_enabled { - let uniforms = uniform! { - model: model, - view: camera.get_view(), - perspective: camera.get_perspective(), - }; - mandelwow_bbox.draw(&mut frame, &uniforms); - } - let text_rot = Matrix4::from_angle_x(cgmath::Deg(-90.0f32)); - let text_pos = Matrix4::from_translation(Vector3 { - x: 0.0, - y: 0.501, - z: 0.0f32, - }) * text_rot; - for x in 0..SEA_XSIZE { - for z in 0..SEA_ZSIZE { - let wave = ((x as f32 / SEA_XSIZE as f32 * PI * 5.0 + t * 2.0).sin() - + (z as f32 / SEA_ZSIZE as f32 * PI * 3.0 + t * 3.0).sin()) - * 0.3; - let model = Matrix4::from_translation( - sea[x][z] - + Vector3 { - x: 0., - y: wave, - z: 0., - }, - ); - let uniforms = uniform! { - model: array4x4(model), - perspview: perspview, - col: [0., (1. - wave).abs() * 0.5, wave.abs()], - }; - shaded_cube.draw(&mut frame, &uniforms); - text.model = model * text_pos; - text.character = (x + z * SEA_XSIZE) as u8 as char; - text.draw(&mut frame, &perspview); - } + *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::from_nanos(16666667)); + match event { + Event::NewEvents(cause) => { + match cause { + event::StartCause::ResumeTimeReached { .. } | event::StartCause::Init => { + world.draw_frame(&camera, t); + }, + _ => {} + } + } _ => (), } - - mandelwow::draw( - &display, - &mut frame, - &mandelwow_program, - model, - &camera, - &bounds, - wow, - ); - - frame.finish().unwrap(); - - let mut action = support::Action::Continue; - events_loop.poll_events(|event| { - if let glium::glutin::Event::WindowEvent { event, .. } = event { - camera.process_input(&event); - match event { - glium::glutin::WindowEvent::CloseRequested => action = support::Action::Stop, - KeyboardInput { input, .. } => { - if input.state == glium::glutin::ElementState::Pressed { - if let Some(key) = input.virtual_keycode { - match key { - VirtualKeyCode::Escape | VirtualKeyCode::Q => { - action = support::Action::Stop; - } - _ => (), + if let Event::WindowEvent { event, .. } = event { + camera.process_input(&event); + match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::KeyboardInput { input, .. } => { + if input.state == event::ElementState::Pressed { + if let Some(key) = input.virtual_keycode { + match key { + VirtualKeyCode::Escape | VirtualKeyCode::Q => { + *control_flow = ControlFlow::Exit; } + _ => (), } } } - /* - KeyboardInput { input: glutin::KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. } } | - KeyboardInput { input: glutin::KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::Q), .. } } => { - return support::Action::Stop - }, - KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::B) } => { - bounding_box_enabled ^= true; - }, - KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::P) } => { - timer.pause ^= true; - }, - KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::PageUp) } => { - timer.t += 0.01; - }, - KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::PageDown) } => { - timer.t -= 0.01; - }, - KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::F10) } => { - screenshot(&display); - }, - KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::F11) } => { - fullscreen ^= true; - if fullscreen { - // Not implemented on Linux - glutin::WindowBuilder::new() - .with_fullscreen(glutin::get_primary_monitor()) - .with_depth_buffer(24) - .rebuild_glium(&display).unwrap(); - } else { - glutin::WindowBuilder::new() - .rebuild_glium(&display).unwrap(); - } - }, - */ - _ => (), } + /* + KeyboardInput { input: glutin::KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. } } | + KeyboardInput { input: glutin::KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::Q), .. } } => { + *control_flow = ControlFlow::Exit; + }, + KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::B) } => { + bounding_box_enabled ^= true; + }, + KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::P) } => { + timer.pause ^= true; + }, + KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::PageUp) } => { + timer.t += 0.01; + }, + KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::PageDown) } => { + timer.t -= 0.01; + }, + KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::F10) } => { + screenshot(&display); + }, + KeyboardInput { state: Pressed, virtual_keycode: Some(VirtualKeyCode::F11) } => { + fullscreen ^= true; + if fullscreen { + // Not implemented on Linux + glutin::WindowBuilder::new() + .with_fullscreen(glutin::get_primary_monitor()) + .with_depth_buffer(24) + .rebuild_glium(&display).unwrap(); + } else { + glutin::WindowBuilder::new() + .rebuild_glium(&display).unwrap(); + } + }, + */ + _ => (), } - }); + } timer.update(); - - action }); } diff --git a/release_wasm.sh b/release_wasm.sh index 477000f..43fdf23 100755 --- a/release_wasm.sh +++ b/release_wasm.sh @@ -1,7 +1,8 @@ set -e export CFLAGS="-O2" export CXXFLAGS="$CFLAGS" -cargo rustc --target wasm32-unknown-emscripten --release --bin mandelwow -- -C link-args='--emrun -s USE_SDL=2 -s ASSERTIONS=2 --preload-file flora.xm' +cargo rustc --target wasm32-unknown-emscripten --release --bin mandelwow -- \ + -C link-args='--emrun -s USE_SDL=2 -s ERROR_ON_MISSING_LIBRARIES=0 -s ASSERTIONS=2 --preload-file flora.xm' cp -a target/wasm32-unknown-emscripten/release/mandelwow.{js,wasm} . cp -a target/wasm32-unknown-emscripten/release/deps/mandelwow.data . emrun . diff --git a/rust-rocket b/rust-rocket index 801bf1d..3ca2cab 160000 --- a/rust-rocket +++ b/rust-rocket @@ -1 +1 @@ -Subproject commit 801bf1dac67576477c8d194fe74fc101f5c32226 +Subproject commit 3ca2caba4878c73bfa4d2d7a36c2f3b943f9888a diff --git a/shaded_cube.rs b/shaded_cube.rs index 6019a12..211f23f 100644 --- a/shaded_cube.rs +++ b/shaded_cube.rs @@ -1,6 +1,7 @@ use glium; use glium::{Display, Program, Surface, implement_vertex}; use glium::index::{IndexBuffer, PrimitiveType}; +use std::rc::Rc; pub fn shaded_program(display: &Display) -> Program { let vertex_shader_src = include_str!("shaders/shaded.vert"); @@ -15,14 +16,14 @@ struct Vertex { } implement_vertex!(Vertex, position, normal); -pub struct ShadedCube<'a> { +pub struct ShadedCube { vertexes: glium::VertexBuffer, - program: &'a Program, + program: Rc, indices: IndexBuffer, } -impl<'a> ShadedCube<'a> { - pub fn new(display: &Display, program: &'a Program) -> ShadedCube<'a> { +impl<'a> ShadedCube { + pub fn new(display: &Display, program: Rc) -> ShadedCube { // x---> // 4 ──────┐ 5 // ╱┆ ╱│ @@ -71,6 +72,6 @@ impl<'a> ShadedCube<'a> { backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise, ..Default::default() }; - frame.draw(&self.vertexes, &self.indices, self.program, uniforms, ¶ms).unwrap(); + frame.draw(&self.vertexes, &self.indices, &self.program, uniforms, ¶ms).unwrap(); } } diff --git a/support/camera.rs b/support/camera.rs index 5ae1c8c..db6c55a 100644 --- a/support/camera.rs +++ b/support/camera.rs @@ -1,7 +1,7 @@ use cgmath::{Matrix4, Vector4}; use cgmath::conv::array4x4; use glium; -use glium::glutin::VirtualKeyCode; +use glium::glutin::event::{ ElementState, VirtualKeyCode, WindowEvent }; use std::f32; use std::f32::consts::PI; use crate::support::vec3::Vec3; @@ -163,9 +163,10 @@ impl CameraState { //println!("camera_dir = {:?}", self.dir); } - pub fn process_input(&mut self, event: &glium::glutin::WindowEvent) { + pub fn process_input(&mut self, event: &WindowEvent) { + //println!("camera event={:?}", event); match event { - &glium::glutin::WindowEvent::CursorMoved { position, .. } => { + &WindowEvent::CursorMoved { position, .. } => { let (x, y) = (position.x as i32, position.y as i32); if self.mouse_x == -1 { // Set initial absolute position. @@ -177,8 +178,8 @@ impl CameraState { self.mouse_x = x; self.mouse_y = y; } - &glium::glutin::WindowEvent::KeyboardInput { input, .. } => { - let pressed = input.state == glium::glutin::ElementState::Pressed; + &WindowEvent::KeyboardInput { input, .. } => { + let pressed = input.state == ElementState::Pressed; let key = match input.virtual_keycode { Some(key) => key, None => return, diff --git a/text.rs b/text.rs index 3d5d73c..4c66a28 100644 --- a/text.rs +++ b/text.rs @@ -1,5 +1,5 @@ use cgmath::conv::array4x4; -use cgmath::{Matrix4, Vector3}; +use cgmath::Matrix4; use glium; use glium::{Display, Program, Surface, implement_vertex, texture, uniform}; use std; @@ -57,12 +57,10 @@ pub struct Text<'a> { index_buffer: glium::IndexBuffer, program: glium::Program, params: glium::DrawParameters<'a>, - pub model: Matrix4, - pub character: char, } impl<'a> Text<'a> { - pub fn new(display: &Display, character: char) -> Text<'_> { + pub fn new(display: &Display) -> Text<'a> { let (w, h, pixels) = c64_font(); let image = glium::texture::RawImage2d { data: std::borrow::Cow::from(pixels), @@ -124,19 +122,17 @@ impl<'a> Text<'a> { index_buffer: index_buffer, program: text_program(display), params: params, - model: Matrix4::from_translation(Vector3::unit_z() * (-1.0)), - character: character, } } - pub fn draw(&self, frame: &mut glium::Frame, perspview: &[[f32; 4]; 4]) { + pub fn draw(&self, frame: &mut glium::Frame, c: char, model: &Matrix4, perspview: &[[f32; 4]; 4]) { let uniforms = uniform! { - model: array4x4(self.model), + model: array4x4(*model), perspview: *perspview, tex: self.tex.sampled() .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest), - index: self.character as i32, + index: c as i32, // RGB values from http://unusedino.de/ec64/technical/misc/vic656x/colors/ bgcolor: srgb([ 64, 50, 133u8]), // 6 - blue fgcolor: srgb([120, 106, 189u8]), // 14 - light blue -- 2.25.1