mouse controls

This commit is contained in:
2025-03-31 22:51:48 -04:00
parent 34292dbe82
commit f1a91b1404
14 changed files with 121 additions and 142 deletions

View File

@@ -17,9 +17,9 @@ It's normal rust, so `cargo run` should fully compile and start it. It requires
## Controls ## Controls
- WASD for movement - WASD or left click & drag for movement
- Scroll to zoom - Scroll to zoom
- Q to take a snapshot - Q or right click to take a snapshot
Snapshots will copy the current texture and let you view it as the new one generates, which is very important for your sanity when you zoom in really far; the undecided regions will be replaced with a darkened version of your snapshot, so you can still know where you are and move around. Snapshots will copy the current texture and let you view it as the new one generates, which is very important for your sanity when you zoom in really far; the undecided regions will be replaced with a darkened version of your snapshot, so you can still know where you are and move around.
@@ -48,8 +48,6 @@ not in order of priority
- add auto snapshot; hard to figure out exactly when to take; maybe wait until at iter threshold dependent on zoom? - add auto snapshot; hard to figure out exactly when to take; maybe wait until at iter threshold dependent on zoom?
- add ability to have multiple snapshots at once, so you can easily navigate around; also fade out snapshots that are far away zoom wise; also maybe save manual ones to disk so you can easily contiune exploring areas - add ability to have multiple snapshots at once, so you can easily navigate around; also fade out snapshots that are far away zoom wise; also maybe save manual ones to disk so you can easily contiune exploring areas
- add checkpointing that somehow lets you save & return to locations; even if this isn't added, add camera reset to easily get back to initial state; would also let you share locations with other people - add checkpointing that somehow lets you save & return to locations; even if this isn't added, add camera reset to easily get back to initial state; would also let you share locations with other people
- zoom in on mouse
- others controls for mouse; click & drag to move, maybe right click could be snapshot
## Cool Screenshots ## Cool Screenshots

View File

@@ -1,5 +1,5 @@
use nalgebra::Vector2; use nalgebra::Vector2;
use std::ops::AddAssign; use std::ops::{AddAssign, Neg};
use crate::util::FixedDec; use crate::util::FixedDec;
@@ -15,20 +15,44 @@ pub struct Zoom {
pub struct Camera { pub struct Camera {
pub pos: Vector2<FixedDec>, pub pos: Vector2<FixedDec>,
pub zoom: Zoom, pub zoom: Zoom,
pub size: Vector2<u32>,
} }
impl Camera { impl Camera {
pub fn scale(&self, size: &Vector2<u32>) -> Vector2<f32> { pub fn world_pos(&self, screen_pos: Vector2<f32>) -> Vector2<FixedDec> {
let fsize: Vector2<f32> = size.cast(); let mut pos = screen_pos
if size.x < size.y { .component_div(&self.size.cast())
.add_scalar(-0.5)
.component_mul(&self.stretch())
.map(FixedDec::from);
pos.y.negate();
pos *= self.zoom.mult().clone();
pos += &self.pos;
pos
}
pub fn world_delta(&self, screen_delta: Vector2<f32>) -> Vector2<FixedDec> {
let mut pos = screen_delta
.component_div(&self.size.cast())
.component_mul(&(self.stretch() * 1.5))
.map(FixedDec::from);
pos.y.negate();
pos *= self.zoom.mult().clone();
pos
}
pub fn stretch(&self) -> Vector2<f32> {
let fsize: Vector2<f32> = self.size.cast();
if self.size.x < self.size.y {
Vector2::new(fsize.x / fsize.y, 1.0) Vector2::new(fsize.x / fsize.y, 1.0)
} else { } else {
Vector2::new(1.0, fsize.y / fsize.x) Vector2::new(1.0, fsize.y / fsize.x)
} }
} }
pub fn inv_scale(&self, size: &Vector2<u32>) -> Vector2<f32> {
let fsize: Vector2<f32> = size.cast(); pub fn inv_stretch(&self) -> Vector2<f32> {
if size.x < size.y { let fsize: Vector2<f32> = self.size.cast();
if self.size.x < self.size.y {
Vector2::new(fsize.y / fsize.x, 1.0) Vector2::new(fsize.y / fsize.x, 1.0)
} else { } else {
Vector2::new(1.0, fsize.x / fsize.y) Vector2::new(1.0, fsize.x / fsize.y)
@@ -39,6 +63,7 @@ impl Camera {
impl Default for Camera { impl Default for Camera {
fn default() -> Self { fn default() -> Self {
Self { Self {
size: Vector2::zeros(),
pos: Vector2::new(-0.5, 0.0).map(FixedDec::from), pos: Vector2::new(-0.5, 0.0).map(FixedDec::from),
zoom: Zoom::new(0, 2.1), zoom: Zoom::new(0, 2.1),
} }

View File

@@ -1,18 +1,46 @@
use std::time::Duration; use std::time::Duration;
use winit::keyboard::KeyCode as K; use winit::{event::MouseButton, keyboard::KeyCode as K};
use crate::util::FixedDec; use crate::util::FixedDec;
use super::Client; use super::Client;
pub struct InputHandling {
pub snapshot: bool,
}
impl InputHandling {
pub fn new() -> Self {
Self { snapshot: false }
}
}
impl Client<'_> { impl Client<'_> {
pub fn handle_input(&mut self, delta: Duration) { pub fn handle_input(&mut self, delta: Duration) {
let Client { input, camera, .. } = self; let Client {
input,
camera,
handling,
..
} = self;
if delta > Duration::from_secs_f32(0.5) {
// skip input handling if lag spike so you don't go flying
return;
}
let per_sec = delta.as_secs_f32(); let per_sec = delta.as_secs_f32();
if input.scroll_delta != 0.0 { if input.scroll_delta != 0.0 {
let old_pos = camera.world_pos(input.mouse_pos);
camera.zoom += input.scroll_delta / 5.0; camera.zoom += input.scroll_delta / 5.0;
let new_pos = camera.world_pos(input.mouse_pos);
camera.pos += old_pos - new_pos;
}
if input.mouse_pressed(MouseButton::Left)
&& (input.mouse_delta.x != 0.0 || input.mouse_delta.y != 0.0)
{
camera.pos -= camera.world_delta(input.mouse_delta);
} }
let speed = FixedDec::from(per_sec * 0.5) * camera.zoom.mult(); let speed = FixedDec::from(per_sec * 0.5) * camera.zoom.mult();
@@ -28,8 +56,8 @@ impl Client<'_> {
if input.pressed(K::KeyD) { if input.pressed(K::KeyD) {
camera.pos.x += &speed; camera.pos.x += &speed;
} }
if input.pressed(K::KeyQ) { if input.just_pressed(K::KeyQ) || input.mouse_just_pressed(MouseButton::Right) {
self.snapshot = true; handling.snapshot = true;
} }
} }
} }

View File

@@ -7,7 +7,7 @@ use winit::{
}; };
pub struct Input { pub struct Input {
pub mouse_pixel_pos: Vector2<f32>, pub mouse_pos: Vector2<f32>,
pub mouse_delta: Vector2<f32>, pub mouse_delta: Vector2<f32>,
pressed: HashSet<KeyCode>, pressed: HashSet<KeyCode>,
@@ -23,7 +23,7 @@ pub struct Input {
impl Input { impl Input {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
mouse_pixel_pos: Vector2::zeros(), mouse_pos: Vector2::zeros(),
mouse_delta: Vector2::zeros(), mouse_delta: Vector2::zeros(),
pressed: HashSet::new(), pressed: HashSet::new(),
just_pressed: HashSet::new(), just_pressed: HashSet::new(),
@@ -67,11 +67,10 @@ impl Input {
}; };
} }
WindowEvent::CursorLeft { .. } => { WindowEvent::CursorLeft { .. } => {
self.pressed.clear(); self.clear();
self.mouse_pressed.clear();
} }
WindowEvent::CursorMoved { position, .. } => { WindowEvent::CursorMoved { position, .. } => {
self.mouse_pixel_pos = Vector2::new(position.x as f32, position.y as f32); self.mouse_pos = Vector2::new(position.x as f32, position.y as f32);
} }
WindowEvent::MouseInput { button, state, .. } => match state { WindowEvent::MouseInput { button, state, .. } => match state {
ElementState::Pressed => { ElementState::Pressed => {

View File

@@ -1,6 +1,7 @@
use std::{sync::Arc, time::Instant}; use std::{sync::Arc, time::Instant};
use camera::Camera; use camera::Camera;
use handle_input::InputHandling;
use input::Input; use input::Input;
use render::Renderer; use render::Renderer;
use winit::{ use winit::{
@@ -23,7 +24,7 @@ pub struct Client<'a> {
exit: bool, exit: bool,
prev_update: Instant, prev_update: Instant,
renderer: Renderer<'a>, renderer: Renderer<'a>,
snapshot: bool, handling: InputHandling,
} }
impl Client<'_> { impl Client<'_> {
@@ -41,7 +42,7 @@ impl Client<'_> {
exit: false, exit: false,
prev_update: Instant::now(), prev_update: Instant::now(),
renderer, renderer,
snapshot: false, handling: InputHandling::new(),
} }
} }
@@ -60,16 +61,17 @@ impl Client<'_> {
pub fn window_event(&mut self, event: WindowEvent) { pub fn window_event(&mut self, event: WindowEvent) {
match event { match event {
WindowEvent::CloseRequested => self.exit = true, WindowEvent::CloseRequested => self.exit = true,
WindowEvent::Resized(size) => self.renderer.resize(size), WindowEvent::Resized(size) => {
self.renderer.resize(size);
self.camera.size = *self.renderer.size();
}
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
self.renderer.render(&self.camera, self.snapshot); self.renderer.render(&self.camera, self.handling.snapshot);
self.snapshot = false; self.handling.snapshot = false;
self.window.request_redraw(); self.window.request_redraw();
} }
WindowEvent::CursorLeft { .. } => { _ => (),
self.input.clear();
}
_ => self.input.update_window(event),
} }
self.input.update_window(event);
} }
} }

View File

@@ -19,7 +19,7 @@ impl ComputeView {
impl Default for ComputeView { impl Default for ComputeView {
fn default() -> Self { fn default() -> Self {
let val = FixedDec::from_parts(false, 0, vec![0, 0, 0]); let val = FixedDec::from_parts(false, 0, vec![0, 0, 0]);
Self::new(true, Vector2::zeros(), 0, &val, &val, &val) Self::new(true, Vector2::zeros(), Vector2::zeros(), 0, &val, &val, &val)
} }
} }
@@ -27,6 +27,7 @@ impl ComputeView {
fn new( fn new(
reset: bool, reset: bool,
dims: Vector2<u32>, dims: Vector2<u32>,
stretch: Vector2<f32>,
level: i32, level: i32,
scale: &FixedDec, scale: &FixedDec,
x: &FixedDec, x: &FixedDec,
@@ -36,6 +37,7 @@ impl ComputeView {
bytes.extend((reset as u32).to_le_bytes()); bytes.extend((reset as u32).to_le_bytes());
bytes.extend(level.to_le_bytes()); bytes.extend(level.to_le_bytes());
bytes.extend(bytemuck::cast_slice(&[dims.x, dims.y])); bytes.extend(bytemuck::cast_slice(&[dims.x, dims.y]));
bytes.extend(bytemuck::cast_slice(&[stretch.x, stretch.y]));
scale.to_bytes(&mut bytes); scale.to_bytes(&mut bytes);
x.to_bytes(&mut bytes); x.to_bytes(&mut bytes);
y.to_bytes(&mut bytes); y.to_bytes(&mut bytes);
@@ -46,7 +48,7 @@ impl ComputeView {
Self { bytes } Self { bytes }
} }
pub fn from_camera_size(camera: &Camera, size: &Vector2<u32>, reset: bool, len: usize) -> Self { pub fn from_camera(camera: &Camera, reset: bool, len: usize) -> Self {
let mut x = camera.pos.x.clone(); let mut x = camera.pos.x.clone();
x.set_whole_len(1); x.set_whole_len(1);
x.set_dec_len(len as i32 - 1); x.set_dec_len(len as i32 - 1);
@@ -54,17 +56,11 @@ impl ComputeView {
y.set_whole_len(1); y.set_whole_len(1);
y.set_dec_len(len as i32 - 1); y.set_dec_len(len as i32 - 1);
let fsize: Vector2<f32> = size.cast(); let stretch = camera.stretch();
let stretch = if size.x < size.y {
Vector2::new(fsize.x / fsize.y, 1.0)
} else {
Vector2::new(1.0, fsize.y / fsize.x)
};
let mut scale = camera.zoom.mult().clone(); let mut scale = camera.zoom.mult().clone();
scale.set_precision(len); scale.set_precision(len);
Self::new(reset, *size, camera.zoom.level(), &scale, &x, &y) Self::new(reset, camera.size, stretch, camera.zoom.level(), &scale, &x, &y)
} }
} }

View File

@@ -36,10 +36,9 @@ impl ComputePipeline {
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt, belt: &mut wgpu::util::StagingBelt,
camera: &Camera, camera: &Camera,
size: &Vector2<u32>,
len: usize, len: usize,
) { ) {
let mut view = ComputeView::from_camera_size(camera, size, false, len); let mut view = ComputeView::from_camera(camera, false, len);
if view != self.old_view { if view != self.old_view {
for (i, b) in 1u32.to_le_bytes().iter().enumerate() { for (i, b) in 1u32.to_le_bytes().iter().enumerate() {
view.bytes[i] = *b; view.bytes[i] = *b;
@@ -49,7 +48,7 @@ impl ComputePipeline {
println!("new len: {}", len); println!("new len: {}", len);
self.old_len = len; self.old_len = len;
self.pipeline = self.pipeline(device, &Self::shader(device, len)); self.pipeline = self.pipeline(device, &Self::shader(device, len));
self.work.set(work_vec(size.x, size.y, len)); self.work.set(work_vec(camera.size.x, camera.size.y, len));
} }
let updated = self.work.update(device, encoder, belt) let updated = self.work.update(device, encoder, belt)
| self.view.update(device, encoder, belt, view.bytes()); | self.view.update(device, encoder, belt, view.bytes());
@@ -66,14 +65,7 @@ impl ComputePipeline {
pass.dispatch_workgroups(240, 135, 1); pass.dispatch_workgroups(240, 135, 1);
} }
pub fn resize( pub fn resize(&mut self, device: &wgpu::Device, size: Vector2<u32>, len: usize) {
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
size: Vector2<u32>,
len: usize,
) {
self.work.set(work_vec(size.x, size.y, len)); self.work.set(work_vec(size.x, size.y, len));
self.old_len = len; self.old_len = len;
self.output.resize( self.output.resize(

View File

@@ -9,6 +9,7 @@ struct View {
reset: u32, reset: u32,
level: i32, level: i32,
dims: vec2<u32>, dims: vec2<u32>,
stretch: vec2<f32>,
scale: FixedDec, scale: FixedDec,
corner_x: FixedDec, corner_x: FixedDec,
corner_y: FixedDec, corner_y: FixedDec,
@@ -28,30 +29,14 @@ fn main(
if id.x > view.dims.x - 1 || id.y > view.dims.y - 1 { if id.x > view.dims.x - 1 || id.y > view.dims.y - 1 {
return; return;
} }
// TODO: actually use width
let varwidth = LEN + 2; let varwidth = LEN + 2;
let workwidth = varwidth * 2 + 1; let workwidth = varwidth * 2 + 1;
let worki = (id.x * view.dims.y + id.y) * workwidth; let worki = (id.x * view.dims.y + id.y) * workwidth;
let xidx = worki + 1; let xidx = worki + 1;
let yidx = xidx + varwidth; let yidx = xidx + varwidth;
// let dec = view.corner_x.dec;
// var rel_x = FixedDec(POS, dec, array<u32, LEN>());
// rel_x.parts[0] = id.x;
// rel_x = shr(rel_x, view.level);
// var rel_y = FixedDec(POS, dec, array<u32, LEN>());
// rel_y.parts[0] = id.y;
// rel_y = shr(rel_y, view.level);
// let cx = add(view.corner_x, rel_x);
// let cy = add(view.corner_y, rel_y);
let fdims = vec2<f32>(view.dims); let fdims = vec2<f32>(view.dims);
var stretch: vec2<f32>; let fpos = (vec2<f32>(id.xy) / fdims - 0.5) * view.stretch;
if fdims.x < fdims.y {
stretch = vec2(fdims.x / fdims.y, 1.0);
} else {
stretch = vec2(1.0, fdims.y / fdims.x);
}
let fpos = (vec2<f32>(id.xy) / fdims - 0.5) * stretch;
let cx = add(mul(from_f32(fpos.x), view.scale), view.corner_x); let cx = add(mul(from_f32(fpos.x), view.scale), view.corner_x);
let cy = add(mul(from_f32(fpos.y), view.scale), view.corner_y); let cy = add(mul(from_f32(fpos.y), view.scale), view.corner_y);
var x: FixedDec; var x: FixedDec;

View File

@@ -122,17 +122,14 @@ impl Renderer<'_> {
} }
pub fn render(&mut self, camera: &Camera, snapshot: bool) { pub fn render(&mut self, camera: &Camera, snapshot: bool) {
// at level 0 I want 2, and should increase respective to bits needed for positioning
// this comes from the fact that I want (0, 2) and (30, 4) self.len = (camera.zoom.level() / 32) as usize + 2;
// probably a much better formula, or better yet let the user select
self.len = (camera.zoom.level() as f32 / 32.0 + 2.0).round() as usize;
self.compute_pipeline.update( self.compute_pipeline.update(
&self.device, &self.device,
&mut self.encoder, &mut self.encoder,
&mut self.staging_belt, &mut self.staging_belt,
camera, camera,
&self.size,
self.len, self.len,
); );
self.chunk_view.update(camera, &self.size, snapshot); self.chunk_view.update(camera, &self.size, snapshot);
@@ -168,8 +165,10 @@ impl Renderer<'_> {
self.config.width = size.width; self.config.width = size.width;
self.config.height = size.height; self.config.height = size.height;
self.surface.configure(&self.device, &self.config); self.surface.configure(&self.device, &self.config);
self.compute_pipeline.resize(&self.device, &mut self.encoder, &mut self.staging_belt, self.size, self.len); self.compute_pipeline
self.render_pipeline.resize(&self.device, self.size, &self.compute_pipeline.output); .resize(&self.device, self.size, self.len);
self.render_pipeline
.resize(&self.device, self.size, &self.compute_pipeline.output);
} }
fn create_encoder(device: &wgpu::Device) -> wgpu::CommandEncoder { fn create_encoder(device: &wgpu::Device) -> wgpu::CommandEncoder {
@@ -177,4 +176,8 @@ impl Renderer<'_> {
label: Some("Render Encoder"), label: Some("Render Encoder"),
}) })
} }
pub fn size(&self) -> &Vector2<u32> {
&self.size
}
} }

View File

@@ -1,7 +1,5 @@
use nalgebra::Vector2; use nalgebra::Vector2;
use crate::client::render::CHUNK_POW;
use super::{Camera, CHUNK_WIDTH}; use super::{Camera, CHUNK_WIDTH};
#[repr(C, align(8))] #[repr(C, align(8))]
@@ -44,10 +42,12 @@ impl WindowView {
// let stretch = size.cast::<f32>() * camera.zoom.rel_zoom() / (CHUNK_WIDTH as f32); // let stretch = size.cast::<f32>() * camera.zoom.rel_zoom() / (CHUNK_WIDTH as f32);
let (pos, stretch) = if let Some(ss_cam) = ss_cam { let (pos, stretch) = if let Some(ss_cam) = ss_cam {
let aspect = camera.inv_scale(size) * 2.0; let aspect = camera.inv_stretch() * 2.0;
let s = camera.zoom.mult() * ss_cam.zoom.inv_mult(); let s = camera.zoom.mult() * ss_cam.zoom.inv_mult();
( (
((&camera.pos - &ss_cam.pos) * ss_cam.zoom.inv_mult().clone()).map(f32::from).component_mul(&aspect), ((&camera.pos - &ss_cam.pos) * ss_cam.zoom.inv_mult().clone())
.map(f32::from)
.component_mul(&aspect),
Vector2::from_element(f32::from(s)), Vector2::from_element(f32::from(s)),
) )
} else { } else {

View File

@@ -21,9 +21,8 @@ var ss_s: sampler;
struct VertexOutput { struct VertexOutput {
@builtin(position) vertex_pos: vec4<f32>, @builtin(position) vertex_pos: vec4<f32>,
@location(0) world_pos: vec2<f32>, @location(0) tex_pos: vec2<f32>,
@location(1) tex_pos: vec2<f32>, @location(1) ss_pos: vec2<f32>,
@location(2) ss_pos: vec2<f32>,
}; };
@vertex @vertex
@@ -35,22 +34,16 @@ fn vs_main(
let pos = vec2<f32>( let pos = vec2<f32>(
f32(vi % 2u), f32(vi % 2u),
f32(vi / 2u), f32(1 - vi / 2u),
) * 2.0 - 1.0; ) * 2.0 - 1.0;
out.vertex_pos = vec4<f32>(pos.x, -pos.y, 0.0, 1.0); out.vertex_pos = vec4<f32>(pos.x, pos.y, 0.0, 1.0);
out.world_pos = pos / 2.0;
out.world_pos.y *= -1.0;
out.world_pos *= view.stretch;
out.world_pos += view.pos;
let pos2 = vec2<f32>( let pos2 = vec2<f32>(
f32(vi % 2u), f32(vi % 2u),
f32(vi / 2u), f32(1 - vi / 2u),
); );
out.tex_pos = pos2; out.tex_pos = pos2;
out.tex_pos.y = 1.0 - out.tex_pos.y; out.ss_pos = pos * view.stretch + view.pos;
let pos3 = vec2(pos.x, -pos.y);
out.ss_pos = pos3 * view.stretch + view.pos;
out.ss_pos = (out.ss_pos + 1.0) / 2.0; out.ss_pos = (out.ss_pos + 1.0) / 2.0;
return out; return out;
@@ -60,16 +53,6 @@ fn vs_main(
fn fs_main( fn fs_main(
in: VertexOutput, in: VertexOutput,
) -> @location(0) vec4<f32> { ) -> @location(0) vec4<f32> {
// let a = textureLoad(chunks, vec2<u32>(0), 0, 0);
// let rc = vec2<i32>(view.rendered_chunks);
// let rcf = vec2<f32>(rc);
// let cposi = vec2<i32>(floor(in.world_pos));
// let cposu = vec2<i32>(
// rem_euclid(cposi.x, rc.x),
// rem_euclid(cposi.y, rc.y)
// );
// let cposf = vec2<f32>(cposu);
// return vec4(cposf / rcf, 0.0, 1.0);
let cur = textureSample(tex, sam, in.tex_pos); let cur = textureSample(tex, sam, in.tex_pos);
let snp_bounds = all(in.ss_pos >= vec2(0.0)) && all(in.ss_pos <= vec2(1.0)); let snp_bounds = all(in.ss_pos >= vec2(0.0)) && all(in.ss_pos <= vec2(1.0));
if all(cur.rgb == vec3(0.0)) && snp_bounds { if all(cur.rgb == vec3(0.0)) && snp_bounds {

View File

@@ -2,15 +2,13 @@ use std::collections::HashSet;
use nalgebra::Vector2; use nalgebra::Vector2;
use crate::{client::camera::Camera, util::FixedDec}; use crate::client::camera::Camera;
use super::{output::WindowView, CHUNK_POW}; use super::output::WindowView;
#[derive(Default)] #[derive(Default)]
pub struct ChunkView { pub struct ChunkView {
pub render: WindowView, pub render: WindowView,
pub chunk_queue: HashSet<Vector2<FixedDec>>,
pub visible_chunks: HashSet<Vector2<FixedDec>>,
pub snapshot: Option<Camera>, pub snapshot: Option<Camera>,
} }
@@ -29,42 +27,5 @@ impl ChunkView {
return; return;
} }
self.render = render; self.render = render;
let corner_offset = ((size / 2).cast() * camera.zoom.rel_zoom())
.map(|x| FixedDec::from(x) >> camera.zoom.level());
let bot_left = &camera.pos - &corner_offset;
let top_right = &camera.pos + &corner_offset;
let mult = FixedDec::one() >> (CHUNK_POW as i32 - camera.zoom.level());
let blc = bot_left
.component_mul(&Vector2::from_element(mult.clone()))
.map(FixedDec::floor);
let trc = top_right
.component_mul(&Vector2::from_element(mult))
.map(FixedDec::floor);
let mut visible = HashSet::new();
let mut x = blc.x.clone();
// while x <= trc.x {
// let mut y = blc.y.clone();
// while y <= trc.y {
// visible.insert(Vector2::new(x.clone(), y.clone()));
// y += FixedDec::one();
// }
// x += FixedDec::one();
// }
let new = visible
.difference(&self.visible_chunks)
.cloned()
.collect::<Vec<_>>();
let old = self
.visible_chunks
.difference(&visible)
.cloned()
.collect::<Vec<_>>();
self.chunk_queue.retain(|p| !old.contains(p));
self.chunk_queue.extend(new);
self.visible_chunks = visible;
} }
} }

View File

@@ -1,5 +1,6 @@
#![feature(bigint_helper_methods)] #![feature(bigint_helper_methods)]
#![feature(int_roundings)] #![feature(int_roundings)]
#![feature(let_chains)]
use client::ClientApp; use client::ClientApp;

View File

@@ -139,6 +139,12 @@ impl FixedDec {
pub fn parts(&self) -> &[u32] { pub fn parts(&self) -> &[u32] {
&self.parts &self.parts
} }
pub fn negate(&mut self) {
if !self.is_zero() {
self.sign = !self.sign;
}
}
} }
impl Display for FixedDec { impl Display for FixedDec {