use crate::{ Input, config::{CAMERA_MOVEMENT_SPEED, CHUNK_SIZE}, sim::{chunk::Chunk, world::World}, }; pub struct Camera { // centre coords pub x: f64, pub y: f64, // zoom scale factor, 1.0 = board <-> window pub zoom: f64, } impl Camera { pub fn handle_camera_input(&mut self, input: &Input, delta_time: f32) { // wasd movement let x: f32 = if input.is_left_pressed { -1.0 } else if input.is_right_pressed { 1.0 } else { 0.0 }; let y: f32 = if input.is_down_pressed { 1.0 } else if input.is_up_pressed { -1.0 } else { 0.0 }; if x == 0.0 && y == 0.0 { return; } let magnitude = (x.powi(2) + y.powi(2)).sqrt(); let adjusted_x = x / magnitude * self.zoom as f32 * CAMERA_MOVEMENT_SPEED * delta_time; let adjusted_y = y / magnitude * self.zoom as f32 * CAMERA_MOVEMENT_SPEED * delta_time; self.x += adjusted_x as f64; self.y += adjusted_y as f64; } pub fn screen_position_to_world(&self, screen_x: f64, screen_y: f64) -> (f64, f64) { let camera_width = self.zoom * f64::from(1600); let camera_height = self.zoom * f64::from(1200); let camera_start_x = self.x - camera_width / 2.0; let camera_start_y = self.y - camera_height / 2.0; ( (screen_x / 1600 as f64 * camera_width) + camera_start_x, (screen_y / 1200 as f64 * camera_height) + camera_start_y, ) } pub fn write_frame_view(&self, frame: &mut [u8], world: &World) { puffin::profile_function!(); // for i in 0..frame.len() / 4 { // let idx = i * 4; // frame[idx] = (i / 1000) as u8; // frame[idx + 1] = 0x00; // frame[idx + 2] = 0x00; // frame[idx + 3] = 0xFF; // } // return; const BG: [u8; 4] = [0x00, 0x00, 0x00, 0xFF]; for px in frame.chunks_exact_mut(4) { px.copy_from_slice(&BG); } // world-space rect covered by the screen let (xl, yl) = self.screen_position_to_world(0.0, 0.0); let (xu, yu) = self.screen_position_to_world(1600 as f64, 1200 as f64); let c = CHUNK_SIZE; let cx0 = (xl.floor() as i32).div_euclid(c); let cx1 = (xu.ceil() as i32).div_euclid(c); let cy0 = (yl.floor() as i32).div_euclid(c); let cy1 = (yu.ceil() as i32).div_euclid(c); let scale = 1.0 / self.zoom; // pixels per cell for cy in cy0..=cy1 { for cx in cx0..=cx1 { let Some(&idx) = world.chunk_position_to_chunk_idx.get(&(cx, cy)) else { continue; }; self.write_chunk(frame, &world.chunks[idx], cx, cy, xl, yl, scale); } } } fn write_chunk( &self, frame: &mut [u8], chunk: &Chunk, cx: i32, cy: i32, xl: f64, yl: f64, scale: f64, ) { let c = CHUNK_SIZE; let w = 1600 as i32; let h = 1200 as i32; for ly in 0..c { let wy = (cy * c + ly) as f64; let sy0 = (((wy - yl) * scale).floor() as i32).max(0); let sy1 = (((wy + 1.0 - yl) * scale).floor() as i32).min(h); if sy0 >= sy1 { continue; } for lx in 0..c { let wx = (cx * c + lx) as f64; let sx0 = (((wx - xl) * scale).floor() as i32).max(0); let sx1 = (((wx + 1.0 - xl) * scale).floor() as i32).min(w); if sx0 >= sx1 { continue; } let color = chunk .get_cell_at_local_position(lx as u8, ly as u8) .material .def() .color; let rgba = [color.0, color.1, color.2, color.3]; for sy in sy0..sy1 { let start = (sy * w + sx0) as usize * 4; let end = (sy * w + sx1) as usize * 4; for px in frame[start..end].chunks_exact_mut(4) { px.copy_from_slice(&rgba); } } } } } }