added snapshot button (q) so you can actually see where you're moving

This commit is contained in:
2025-03-30 16:41:07 -04:00
parent 44b6887e00
commit 2e11d2c2ab
11 changed files with 137 additions and 15 deletions

View File

@@ -8,6 +8,7 @@ pub struct Zoom {
exp: f32, exp: f32,
level: i32, level: i32,
mult: FixedDec, mult: FixedDec,
inv_mult: FixedDec,
} }
#[derive(Clone)] #[derive(Clone)]
@@ -41,12 +42,16 @@ impl Zoom {
Self { Self {
exp: scale, exp: scale,
level, level,
mult: mult(level, scale), mult: zoom_mult(level, scale),
inv_mult: inv_zoom_mult(level, scale),
} }
} }
pub fn mult(&self) -> &FixedDec { pub fn mult(&self) -> &FixedDec {
&self.mult &self.mult
} }
pub fn inv_mult(&self) -> &FixedDec {
&self.inv_mult
}
pub fn level(&self) -> i32 { pub fn level(&self) -> i32 {
self.level self.level
} }
@@ -67,10 +72,15 @@ impl AddAssign<f32> for Zoom {
self.exp -= 1.0; self.exp -= 1.0;
self.level -= 1; self.level -= 1;
} }
self.mult = mult(self.level, self.exp); self.mult = zoom_mult(self.level, self.exp);
self.inv_mult = inv_zoom_mult(self.level, self.exp);
} }
} }
pub fn mult(level: i32, exp: f32) -> FixedDec { pub fn zoom_mult(level: i32, exp: f32) -> FixedDec {
(FixedDec::from(1) >> level) * FixedDec::from(exp.exp2()) (FixedDec::from(1) >> level) * FixedDec::from(exp.exp2())
} }
pub fn inv_zoom_mult(level: i32, exp: f32) -> FixedDec {
(FixedDec::from(1) << level) * FixedDec::from(1.0 / exp.exp2())
}

View File

@@ -28,5 +28,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) {
self.snapshot = true;
}
} }
} }

View File

@@ -23,6 +23,7 @@ pub struct Client<'a> {
exit: bool, exit: bool,
prev_update: Instant, prev_update: Instant,
renderer: Renderer<'a>, renderer: Renderer<'a>,
snapshot: bool,
} }
impl Client<'_> { impl Client<'_> {
@@ -40,6 +41,7 @@ impl Client<'_> {
exit: false, exit: false,
prev_update: Instant::now(), prev_update: Instant::now(),
renderer, renderer,
snapshot: false,
} }
} }
@@ -60,7 +62,8 @@ impl Client<'_> {
WindowEvent::CloseRequested => self.exit = true, WindowEvent::CloseRequested => self.exit = true,
WindowEvent::Resized(size) => self.renderer.resize(size), WindowEvent::Resized(size) => self.renderer.resize(size),
WindowEvent::RedrawRequested => { WindowEvent::RedrawRequested => {
self.renderer.render(&self.camera); self.renderer.render(&self.camera, self.snapshot);
self.snapshot = false;
self.window.request_redraw(); self.window.request_redraw();
} }
WindowEvent::CursorLeft { .. } => { WindowEvent::CursorLeft { .. } => {

View File

@@ -37,7 +37,7 @@ impl Layout {
sample_count: 1, sample_count: 1,
dimension: wgpu::TextureDimension::D2, dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm, format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING, usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC,
view_formats: &[], view_formats: &[],
}; };
let output = Texture::init( let output = Texture::init(

View File

@@ -46,6 +46,7 @@ impl ComputePipeline {
} }
} }
if len != self.old_len { if len != self.old_len {
println!("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(size.x, size.y, len));

View File

@@ -121,12 +121,11 @@ impl Renderer<'_> {
} }
} }
pub fn render(&mut self, camera: &Camera) { pub fn render(&mut self, camera: &Camera, snapshot: bool) {
// this comes from the fact that I want (0, 2) and (30, 4)
// probably a much better formula, or better yet let the user select
self.len = (camera.zoom.level() as f32 / 15.0 + 2.0).round() as usize; self.len = (camera.zoom.level() as f32 / 15.0 + 2.0).round() as usize;
println!("{}", self.len);
// let new = (camera.zoom.level() as f32 / 15.0 + 2.0).round() as usize;
// println!("{}", new);
self.compute_pipeline.update( self.compute_pipeline.update(
&self.device, &self.device,
@@ -136,12 +135,14 @@ impl Renderer<'_> {
&self.size, &self.size,
self.len, self.len,
); );
self.chunk_view.update(camera, &self.size); self.chunk_view.update(camera, &self.size, snapshot);
self.render_pipeline.update( self.render_pipeline.update(
&self.device, &self.device,
&mut self.encoder, &mut self.encoder,
&mut self.staging_belt, &mut self.staging_belt,
&self.chunk_view.render, &self.chunk_view.render,
&self.compute_pipeline.output,
snapshot,
); );
let mut encoder = std::mem::replace(&mut self.encoder, Self::create_encoder(&self.device)); let mut encoder = std::mem::replace(&mut self.encoder, Self::create_encoder(&self.device));

View File

@@ -10,13 +10,20 @@ pub struct WindowView {
pub stretch: Vector2<f32>, pub stretch: Vector2<f32>,
pub pos: Vector2<f32>, pub pos: Vector2<f32>,
pub rendered_chunks: Vector2<u32>, pub rendered_chunks: Vector2<u32>,
pub snapshot: u32,
} }
unsafe impl bytemuck::Pod for WindowView {} unsafe impl bytemuck::Pod for WindowView {}
unsafe impl bytemuck::Zeroable for WindowView {} unsafe impl bytemuck::Zeroable for WindowView {}
impl WindowView { impl WindowView {
pub fn from_camera_size(camera: &Camera, size: &Vector2<u32>) -> Self { pub fn from_camera_size(
camera: &Camera,
ss_cam: Option<&Camera>,
size: &Vector2<u32>,
snapshot: bool,
) -> Self {
// TODO: most of this is useless and just preparation for chunked textures if I add them
let visible_chunks = (size * 2 / CHUNK_WIDTH).add_scalar(1); let visible_chunks = (size * 2 / CHUNK_WIDTH).add_scalar(1);
let rendered_chunks = Vector2::new( let rendered_chunks = Vector2::new(
visible_chunks.x.next_power_of_two(), visible_chunks.x.next_power_of_two(),
@@ -36,10 +43,21 @@ 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 s = camera.zoom.mult() * ss_cam.zoom.inv_mult();
(
((&camera.pos - &ss_cam.pos) * ss_cam.zoom.inv_mult().clone()).map(f32::from) * 2.0,
Vector2::from_element(f32::from(s)),
)
} else {
(Vector2::default(), Vector2::default())
};
Self { Self {
pos, pos,
stretch, stretch,
rendered_chunks, rendered_chunks,
snapshot: snapshot as u32,
} }
} }
} }

View File

@@ -13,6 +13,7 @@ pub struct Layout {
format: wgpu::TextureFormat, format: wgpu::TextureFormat,
pub view: Storage, pub view: Storage,
pub chunks: ResizableTexture, pub chunks: ResizableTexture,
pub snapshot: Texture,
} }
pub const LABEL: &str = file!(); pub const LABEL: &str = file!();
@@ -46,6 +47,29 @@ impl Layout {
}; };
let chunks = ResizableTexture::new(device, texture_desc, view_desc); let chunks = ResizableTexture::new(device, texture_desc, view_desc);
let desc = wgpu::TextureDescriptor {
label: Some("compute output"),
size: wgpu::Extent3d {
width: config.width,
height: config.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::STORAGE_BINDING
| wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::COPY_DST,
view_formats: &[],
};
let snapshot = Texture::init(
device,
desc,
wgpu::TextureViewDescriptor::default(),
wgpu::SamplerDescriptor::default(),
);
let render_bind_layout = let render_bind_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[ entries: &[
@@ -80,6 +104,22 @@ impl Layout {
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None, count: None,
}, },
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStages::FRAGMENT | wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
], ],
label: Some(LABEL), label: Some(LABEL),
}); });
@@ -97,6 +137,7 @@ impl Layout {
render_bind_layout, render_bind_layout,
render_pipeline_layout, render_pipeline_layout,
format: config.format, format: config.format,
snapshot,
} }
} }
@@ -108,6 +149,8 @@ impl Layout {
self.chunks.view_entry(1), self.chunks.view_entry(1),
input.view_bind_group_entry(2), input.view_bind_group_entry(2),
input.sampler_bind_group_entry(3), input.sampler_bind_group_entry(3),
self.snapshot.view_bind_group_entry(4),
self.snapshot.sampler_bind_group_entry(5),
], ],
label: Some(LABEL), label: Some(LABEL),
}) })

View File

@@ -39,7 +39,31 @@ impl RenderPipeline {
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt, belt: &mut wgpu::util::StagingBelt,
view: &WindowView, view: &WindowView,
input: &Texture,
snapshot: bool,
) { ) {
if snapshot {
let size = input.texture.size();
if self.snapshot.texture.size() != size {
self.snapshot.resize(device, size);
}
encoder.copy_texture_to_texture(
wgpu::TexelCopyTextureInfoBase {
texture: &input.texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
wgpu::TexelCopyTextureInfoBase {
texture: &self.snapshot.texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
size,
);
self.bind_group = self.bind_group(device, input);
}
self.view self.view
.update(device, encoder, belt, bytemuck::bytes_of(view)); .update(device, encoder, belt, bytemuck::bytes_of(view));
} }

View File

@@ -2,6 +2,7 @@ struct View {
stretch: vec2<f32>, stretch: vec2<f32>,
pos: vec2<f32>, pos: vec2<f32>,
rendered_chunks: vec2<u32>, rendered_chunks: vec2<u32>,
snapshot: u32,
} }
@group(0) @binding(0) @group(0) @binding(0)
@@ -13,11 +14,16 @@ var chunks: texture_2d_array<u32>;
var tex: texture_2d<f32>; var tex: texture_2d<f32>;
@group(0) @binding(3) @group(0) @binding(3)
var sam: sampler; var sam: sampler;
@group(0) @binding(4)
var ss_t: texture_2d<f32>;
@group(0) @binding(5)
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) world_pos: vec2<f32>,
@location(1) tex_pos: vec2<f32>, @location(1) tex_pos: vec2<f32>,
@location(2) ss_pos: vec2<f32>,
}; };
@vertex @vertex
@@ -43,6 +49,9 @@ fn vs_main(
); );
out.tex_pos = pos2; out.tex_pos = pos2;
out.tex_pos.y = 1.0 - out.tex_pos.y; out.tex_pos.y = 1.0 - out.tex_pos.y;
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;
return out; return out;
} }
@@ -61,7 +70,14 @@ fn fs_main(
// ); // );
// let cposf = vec2<f32>(cposu); // let cposf = vec2<f32>(cposu);
// return vec4(cposf / rcf, 0.0, 1.0); // return vec4(cposf / rcf, 0.0, 1.0);
return 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));
if all(cur.rgb == vec3(0.0)) && snp_bounds {
let snp = textureSample(ss_t, ss_s, in.ss_pos).rgb;
return vec4(snp * 0.3, 1.0);
} else {
return cur;
}
} }
fn div_euclid(x: i32, y: i32) -> i32 { fn div_euclid(x: i32, y: i32) -> i32 {

View File

@@ -11,6 +11,7 @@ pub struct ChunkView {
pub render: WindowView, pub render: WindowView,
pub chunk_queue: HashSet<Vector2<FixedDec>>, pub chunk_queue: HashSet<Vector2<FixedDec>>,
pub visible_chunks: HashSet<Vector2<FixedDec>>, pub visible_chunks: HashSet<Vector2<FixedDec>>,
pub snapshot: Option<Camera>,
} }
impl ChunkView { impl ChunkView {
@@ -18,8 +19,11 @@ impl ChunkView {
Self::default() Self::default()
} }
pub fn update(&mut self, camera: &Camera, size: &Vector2<u32>) { pub fn update(&mut self, camera: &Camera, size: &Vector2<u32>, snapshot: bool) {
let render = WindowView::from_camera_size(camera, size); if snapshot {
self.snapshot = Some(camera.clone());
}
let render = WindowView::from_camera_size(camera, self.snapshot.as_ref(), size, snapshot);
if self.render == render { if self.render == render {
return; return;
@@ -63,4 +67,3 @@ impl ChunkView {
self.visible_chunks = visible; self.visible_chunks = visible;
} }
} }