summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs184
1 files changed, 118 insertions, 66 deletions
diff --git a/src/main.rs b/src/main.rs
index 64e57df..02920d6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,19 +7,28 @@ use egui::Id;
use egui_wgpu::{RendererOptions, ScreenDescriptor};
use egui_winit::egui::{self, Context};
use pixels::{Pixels, ScalingMode, SurfaceTexture};
-use std::time::{Duration, Instant};
+use std::{
+ cmp::{max, min},
+ time::{Duration, Instant},
+};
use winit::{
application::ApplicationHandler,
- event::{ElementState, MouseButton, WindowEvent},
+ event::{
+ ElementState, KeyEvent, MouseButton,
+ WindowEvent::{self},
+ },
event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
- keyboard::Key::{self},
+ keyboard::{KeyCode, PhysicalKey},
window::Window,
};
use crate::{
- camera::{CameraState, screen_position_to_board, write_frame_view},
+ camera::Camera,
config::{PIXEL_BUFFER_HEIGHT, PIXEL_BUFFER_WIDTH, WINDOW_TITLE},
- sim::{board::Board, overlay::create_compute_combined_overlay_offset},
+ sim::{
+ board::Board, materials::MaterialId, overlay::create_compute_combined_overlay_offset,
+ sim::sim_tick,
+ },
ui::draw_egui,
};
@@ -27,21 +36,22 @@ pub type Error = Box<dyn std::error::Error>;
pub type Result<T> = std::result::Result<T, Error>;
struct Config {
+ show_ticks: bool,
fps: u16,
- brush_size: u8,
+ brush_radius: u8,
+ brush_material: MaterialId,
}
struct Input {
- last_mouse_pos_on_screen: (f64, f64),
- last_mouse_pos_on_board: (i32, i32),
- is_lmb_down: bool,
-}
+ last_mouse_pos_on_screen: Option<(f64, f64)>,
+ last_mouse_pos_on_board: Option<(i32, i32)>,
+ is_lmb_pressed: bool,
-struct State {
- // debug
- red_level: u8,
- green_level: u8,
- blue_level: u8,
+ // keybindings
+ is_up_pressed: bool,
+ is_left_pressed: bool,
+ is_down_pressed: bool,
+ is_right_pressed: bool,
}
struct Diagnostics {
@@ -56,22 +66,24 @@ struct App {
window: Option<&'static Window>,
pixels: Option<Pixels<'static>>,
- // input state
input: Input,
- // camera state
- camera: Option<CameraState>,
+ camera: Option<Camera>,
- // game state
board: Option<Board>,
+ // sim state
+ // the last/current (not yet completed) seqno
+ sim_seqno: u64,
+ sim_paused: bool,
+ ignore_pause_next_tick: bool,
+
// used to wait for drawing
last_frame_requested: Instant,
// used to compute delta_time
last_frame_real: Instant,
config: Config,
- state: State,
diagnostics: Diagnostics,
}
@@ -85,12 +97,17 @@ impl Default for App {
pixels: None,
input: Input {
- last_mouse_pos_on_screen: (0.0, 0.0),
- last_mouse_pos_on_board: (0, 0),
- is_lmb_down: false,
+ last_mouse_pos_on_screen: None,
+ last_mouse_pos_on_board: None,
+
+ is_lmb_pressed: false,
+ is_up_pressed: false,
+ is_left_pressed: false,
+ is_down_pressed: false,
+ is_right_pressed: false,
},
- camera: Some(CameraState {
+ camera: Some(Camera {
x: 0.0,
y: 0.0,
zoom: 0.5,
@@ -98,17 +115,18 @@ impl Default for App {
board: Some(Board::empty()),
+ sim_seqno: 0,
+ sim_paused: false,
+ ignore_pause_next_tick: false,
+
last_frame_requested: Instant::now(),
last_frame_real: Instant::now(),
config: Config {
fps: 120,
- brush_size: 10,
- },
- state: State {
- red_level: 0xFF,
- green_level: 0xFF,
- blue_level: 0xFF,
+ show_ticks: false,
+ brush_radius: 10,
+ brush_material: MaterialId::Sand,
},
diagnostics: Diagnostics { fps: 0.0 },
}
@@ -174,25 +192,46 @@ impl ApplicationHandler for App {
}
match event {
- WindowEvent::KeyboardInput { event, .. } => match event.logical_key {
- Key::Character(char) => {
- if char == "z" {
- camera.zoom += 0.1;
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ physical_key: PhysicalKey::Code(code),
+ state,
+ ..
+ },
+ ..
+ } => {
+ let pressed = state.is_pressed();
+ match code {
+ KeyCode::KeyW => self.input.is_up_pressed = pressed,
+ KeyCode::KeyA => self.input.is_left_pressed = pressed,
+ KeyCode::KeyS => self.input.is_down_pressed = pressed,
+ KeyCode::KeyD => self.input.is_right_pressed = pressed,
+ KeyCode::KeyC => self.board = Some(Board::empty()),
+ KeyCode::Space => {
+ if pressed {
+ self.sim_paused = !self.sim_paused
+ }
+ }
+ KeyCode::KeyX => {
+ if pressed {
+ self.ignore_pause_next_tick = true
+ }
}
+ _ => {}
}
- _ => {}
- },
+ }
WindowEvent::CursorMoved { position, .. } => {
- self.input.last_mouse_pos_on_screen = (position.x, position.y);
+ self.input.last_mouse_pos_on_screen = Some((position.x, position.y));
self.input.last_mouse_pos_on_board = pixels
.window_pos_to_pixel((position.x as f32, position.y as f32))
- .map(|v| screen_position_to_board(board, camera, v.0 as f64, v.1 as f64))
+ .map(|v| camera.screen_position_to_board(board, v.0 as f64, v.1 as f64))
.map(|v| (v.0 as i32, v.1 as i32))
- .unwrap();
+ .ok()
}
WindowEvent::MouseInput { state, button, .. } => {
if button == MouseButton::Left {
- self.input.is_lmb_down = state == ElementState::Pressed
+ self.input.is_lmb_pressed = state == ElementState::Pressed
}
}
WindowEvent::Resized(size) => {
@@ -212,54 +251,68 @@ impl ApplicationHandler for App {
// TODO: can smooth and round this
self.diagnostics.fps = instantaneous_fps;
+ // apply inputs
+ camera.handle_camera_input(&self.input, delta_time);
+
// pixels/camera logic
let frame = pixels.frame_mut();
frame.fill(0);
// --TEST DRAWING--
- if self.input.is_lmb_down {
+ if self.input.is_lmb_pressed && self.input.last_mouse_pos_on_board.is_some() {
// start with the bounding box of the drawing brush circle + some margin
- let bb_xl = self.input.last_mouse_pos_on_board.0
- - self.config.brush_size as i32 / 2
- - 5;
- let bb_xu = self.input.last_mouse_pos_on_board.0
- + self.config.brush_size as i32 / 2
- + 5;
- let bb_yl = self.input.last_mouse_pos_on_board.1
- - self.config.brush_size as i32 / 2
- - 5;
- let bb_yu = self.input.last_mouse_pos_on_board.1
- + self.config.brush_size as i32 / 2
- + 5;
+ // clamp the bounding box to the board sie
+ // TODO better way to do this without unwrap?
+ let bb_xl = max(
+ self.input.last_mouse_pos_on_board.unwrap().0
+ - self.config.brush_radius as i32,
+ -((board.size_x / 2) as i32),
+ );
+ let bb_xu = min(
+ self.input.last_mouse_pos_on_board.unwrap().0
+ + self.config.brush_radius as i32,
+ (board.size_x / 2) as i32,
+ );
+ let bb_yl = max(
+ self.input.last_mouse_pos_on_board.unwrap().1
+ - self.config.brush_radius as i32,
+ -((board.size_y / 2) as i32),
+ );
+ let bb_yu = min(
+ self.input.last_mouse_pos_on_board.unwrap().1
+ + self.config.brush_radius as i32,
+ (board.size_y / 2) as i32,
+ );
// for each point, check if the distance is less than the brush size and write the pixel
for x in bb_xl..bb_xu {
for y in bb_yl..bb_yu {
// brush/selection
- if (((x - self.input.last_mouse_pos_on_board.0).pow(2)
- + (y - self.input.last_mouse_pos_on_board.1).pow(2))
- as f32)
- .sqrt()
- < self.config.brush_size as f32
+ if ((x - self.input.last_mouse_pos_on_board.unwrap().0).pow(2)
+ + (y - self.input.last_mouse_pos_on_board.unwrap().1).pow(2))
+ < (self.config.brush_radius as i32).pow(2)
{
board.set_cell_at_position(
x,
y,
- sim::board::Cell {
- material: 1,
- velocity_x: 0,
- velocity_y: 0,
- flags: 0,
- },
+ sim::board::Cell::from_material(self.config.brush_material),
);
}
}
}
}
+ // TODO check if we need to run another sim tick given the sim speed
+ // SIM logic
+ if !self.sim_paused || self.ignore_pause_next_tick {
+ sim_tick(board, self.sim_seqno, delta_time);
+ self.sim_seqno += 1;
+ self.ignore_pause_next_tick = false;
+ }
+
let get_overlay =
create_compute_combined_overlay_offset(board, &self.config, &self.input);
- write_frame_view(frame, board, camera, get_overlay);
+ camera.write_frame_view(frame, board, get_overlay);
// egui logic
let raw_input = egui_state.take_egui_input(window);
@@ -272,7 +325,6 @@ impl ApplicationHandler for App {
draw_egui(
panel_ui,
&mut self.config,
- &mut self.state,
camera,
&self.diagnostics,
&self.input,