diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 193 |
1 files changed, 131 insertions, 62 deletions
diff --git a/src/main.rs b/src/main.rs index eaeaf9d..8f8859b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,5 @@ /* @TODO: -- pause screen - reload settings.txt when changed - strip ' ' and '\n' from *inside* string - flash error on bad string (see @TODO(error handling)) @@ -42,7 +41,17 @@ type Mat3 = Matrix3<f32>; type Mat4 = Matrix4<f32>; type Rot3 = Rotation3<f32>; -const MENU_SCALE: f32 = 0.5; +const MENU_SCALE: f32 = 0.6; +#[derive(Clone, Copy)] +enum MenuButton { + Resume, + Quit +} +/// array of buttons in menu.png. (y, height, button) +const MENU_BUTTONS: &[(f32, f32, MenuButton)] = &[ + (375.0, 135.0, MenuButton::Resume), + (605.0, 165.0, MenuButton::Quit), +]; #[repr(i32)] #[derive(Clone, Copy)] @@ -233,6 +242,7 @@ struct State { show_debug_info: bool, fullscreen: bool, esc_menu: bool, + quit: bool, frame_time: Instant, programs: Programs, config: sdf::SceneConfig, @@ -360,6 +370,7 @@ impl State { main_array, test_array, esc_menu: false, + quit: false, post_array, scene_list, settings, @@ -436,7 +447,7 @@ impl State { self.flash_icon = icon; } - fn render_resolution(&self) -> (i32, i32) { + fn get_render_resolution(&self) -> (i32, i32) { let scale = self.settings.get_f32("scale").unwrap_or(1.0); if scale <= 0.0 || scale > 100.0 { win::display_error_message(&format!("bad scale: {scale}")); @@ -450,6 +461,79 @@ impl State { (w, h) } + /// render the SDF to the main framebuffer + fn render_main(&mut self) { + let render_resolution = self.get_render_resolution(); + let window = &mut self.window; + let view = &self.view; + window.viewport(0, 0, render_resolution.0, render_resolution.1); + + window.clear_screen(win::ColorF32::BLACK); + window.use_program(&self.programs.main); + window.bind_framebuffer(Some(&self.main_framebuffer)); + window.uniform1f( + "u_aspect_ratio", + render_resolution.0 as f32 / render_resolution.1 as f32, + ); + { + let (w, h) = window.size(); + window.uniform2f("u_screen_size", w as f32, h as f32); + } + window.uniform1f("u_time", view.time as f32); + window.uniform1f( + "u_fov", + self.settings.get_f32("fov").unwrap_or(45.0).to_radians(), + ); + window.uniform1f( + "u_focal_length", + self.settings.get_f32("focal-length").unwrap_or(1.0), + ); + window.uniform1f("u_level_set", view.level_set); + window.uniform1i("u_hsv", self.settings.get_i32("hsv").unwrap_or(0)); + let antialiasing = self.settings.get_i32("antialiasing").unwrap_or(1); + window.uniform2i("u_antialiasing", antialiasing, antialiasing); + window.uniform1i( + "u_iterations", + self.settings.get_i32("max-iterations").unwrap_or(30), + ); + window.uniform1f( + "u_distance_threshold", + self.settings.get_f32("distance-threshold").unwrap_or(0.02), + ); + window.uniform3x3f("u_rotation", view.rotation().as_slice()); + window.uniform3f_slice("u_translation", view.pos.as_slice()); + window.uniform4f_color("u_flash", self.flash); + window.uniform1i("u_flash_icon", self.flash_icon as i32); + + self.main_array.draw(); + } + + /// draw the main framebuffer to the screen, apply postprocessing + fn render_post(&mut self) { + let highlight_button = self.menu_button_at_pos(self.window.get_mouse_pos()); + let render_resolution = self.get_render_resolution(); + let window = &mut self.window; + window.bind_framebuffer(None); + window.viewport_full_screen(); + window.use_program(&self.programs.post); + window.active_texture(0, &self.main_framebuffer_texture); + window.active_texture(1, &self.menu_texture); + window.uniform1f("u_paused", if self.esc_menu { 1.0 } else { 0.0 }); + window.uniform_texture("u_main_texture", 0); + window.uniform_texture("u_menu_texture", 1); + window.uniform1f( + "u_aspect_ratio", + render_resolution.0 as f32 / render_resolution.1 as f32, + ); + window.uniform1f("u_menu_scale", MENU_SCALE); + if let Some((_, y1, y2)) = highlight_button { + window.uniform2f("u_highlight_button", y1, y2); + } else { + window.uniform2f("u_highlight_button", 0.0, 0.0); + } + self.post_array.draw(); + } + /// save a screenshot fn take_screenshot(&mut self) -> Result<(), String> { let texture = &self.main_framebuffer_texture; @@ -489,6 +573,32 @@ impl State { self.flash(Icon::Screenshot); Ok(()) } + + /// returns Some(button, v1, v2) which is a bit weird but oh well + fn menu_button_at_pos(&self, screen_pos: (i32, i32)) -> Option<(MenuButton, f32, f32)> { + let window_height = self.window.size().1 as f32; + let texture_height = self.menu_texture.height() as f32; + let y = screen_pos.1 as f32 / window_height as f32; + for &(y1, h, button) in MENU_BUTTONS { + let y1 = y1 / texture_height; + let h = h / texture_height; + let y2 = y1 + h; + let y1 = (y1 - 0.5) * MENU_SCALE + 0.5; + let y2 = (y2 - 0.5) * MENU_SCALE + 0.5; + if y >= y1 && y <= y2 { + return Some((button, 1.0 - y2, 1.0 - y1)); + } + } + None + } + + fn press_menu_button(&mut self, button: MenuButton) { + use MenuButton::*; + match button { + Resume => self.esc_menu = false, + Quit => self.quit = true, + } + } // returns false if we should quit fn frame(&mut self) -> bool { @@ -509,6 +619,7 @@ impl State { while let Some(event) = self.window.next_event() { use win::Event::*; use win::Key::*; + use win::MouseButton; match event { Quit => return false, KeyDown { @@ -595,6 +706,13 @@ impl State { .pitch_by(-yrel as f32 * mouse_sensitivity * frame_dt); } } + MouseButtonDown { button: MouseButton::Left, x, y, .. } => { + if self.esc_menu { + if let Some((menu_button, _, _)) = self.menu_button_at_pos((x, y)) { + self.press_menu_button(menu_button); + } + } + } _ => {} } } @@ -666,7 +784,7 @@ impl State { self.view.level_set += dl * level_set_amount; } - let render_resolution = self.render_resolution(); + let render_resolution = self.get_render_resolution(); if render_resolution != self.main_framebuffer_size { // window resized. create new framebuffer let result = self.main_framebuffer_texture.set_data::<ColorU8>( @@ -687,77 +805,28 @@ impl State { self.main_framebuffer_size = render_resolution; } - let window = &mut self.window; - let view = &self.view; - window.viewport(0, 0, render_resolution.0, render_resolution.1); - - window.clear_screen(win::ColorF32::BLACK); - window.use_program(&self.programs.main); - window.bind_framebuffer(Some(&self.main_framebuffer)); - window.uniform1f( - "u_aspect_ratio", - render_resolution.0 as f32 / render_resolution.1 as f32, - ); - { - let (w, h) = window.size(); - window.uniform2f("u_screen_size", w as f32, h as f32); + // if the escape menu is open, stop rendering the SDF. + // the framebuffer contents will stay the same. + // this lowers GPU usage (and increases framerate). + if !self.esc_menu { + self.render_main(); } - window.uniform1f("u_time", view.time as f32); - window.uniform1f( - "u_fov", - self.settings.get_f32("fov").unwrap_or(45.0).to_radians(), - ); - window.uniform1f( - "u_focal_length", - self.settings.get_f32("focal-length").unwrap_or(1.0), - ); - window.uniform1f("u_level_set", view.level_set); - window.uniform1i("u_hsv", self.settings.get_i32("hsv").unwrap_or(0)); - let antialiasing = self.settings.get_i32("antialiasing").unwrap_or(1); - window.uniform2i("u_antialiasing", antialiasing, antialiasing); - window.uniform1i( - "u_iterations", - self.settings.get_i32("max-iterations").unwrap_or(30), - ); - window.uniform1f( - "u_distance_threshold", - self.settings.get_f32("distance-threshold").unwrap_or(0.02), - ); - window.uniform3x3f("u_rotation", view.rotation().as_slice()); - window.uniform3f_slice("u_translation", view.pos.as_slice()); - window.uniform4f_color("u_flash", self.flash); - window.uniform1i("u_flash_icon", self.flash_icon as i32); - + self.flash.a = f32::max(self.flash.a - frame_dt * (2.0 - 1.0 * self.flash.a), 0.0); if self.flash.a <= 0.0 { // icon is no longer visible self.flash_icon = Icon::None; } - self.main_array.draw(); - - window.bind_framebuffer(None); - window.viewport_full_screen(); - window.use_program(&self.programs.post); - window.active_texture(0, &self.main_framebuffer_texture); - window.active_texture(1, &self.menu_texture); - window.uniform1f("u_paused", if self.esc_menu { 1.0 } else { 0.0 }); - window.uniform_texture("u_main_texture", 0); - window.uniform_texture("u_menu_texture", 1); - window.uniform1f( - "u_aspect_ratio", - render_resolution.0 as f32 / render_resolution.1 as f32, - ); - window.uniform1f("u_menu_scale", MENU_SCALE); - self.post_array.draw(); + self.render_post(); - window.swap(); + self.window.swap(); if self.show_debug_info { println!("frame time = {:?}ms", frame_dt * 1000.0); } - true + !self.quit } } |