891 lines
32 KiB
Rust
891 lines
32 KiB
Rust
#![feature(generic_const_exprs)]
|
||
#![feature(float_algebraic)]
|
||
|
||
use std::collections::HashMap;
|
||
use std::sync::Arc;
|
||
use std::sync::mpsc::sync_channel;
|
||
|
||
use bytemuck::Pod;
|
||
use bytemuck::Zeroable;
|
||
use bytemuck::cast_slice;
|
||
use crevice::std140::AsStd140;
|
||
use egui::Color32;
|
||
use egui::mutex::Mutex;
|
||
use egui_plot::BarChart;
|
||
use glam::Mat4;
|
||
use glam::Vec3;
|
||
use glam::Vec4;
|
||
use itertools::Itertools;
|
||
use rayon::iter::IndexedParallelIterator;
|
||
use rayon::iter::IntoParallelRefIterator;
|
||
use rayon::iter::ParallelIterator;
|
||
use wgpu::Buffer;
|
||
use wgpu::BufferUsages;
|
||
use wgpu::Device;
|
||
use wgpu::Extent3d;
|
||
use wgpu::Features;
|
||
use wgpu::InstanceDescriptor;
|
||
use wgpu::InstanceFlags;
|
||
use wgpu::MemoryBudgetThresholds;
|
||
use wgpu::Operations;
|
||
use wgpu::RenderPipeline;
|
||
use wgpu::Texture;
|
||
use wgpu::TextureUsages;
|
||
use wgpu::TextureView;
|
||
use wgpu::util::BufferInitDescriptor;
|
||
use wgpu::util::DeviceExt;
|
||
use wgpu::util::DownloadBuffer;
|
||
use winit::application::ApplicationHandler;
|
||
use winit::event::DeviceEvent;
|
||
use winit::event::MouseScrollDelta;
|
||
use winit::event::WindowEvent;
|
||
use winit::event_loop;
|
||
use winit::event_loop::ActiveEventLoop;
|
||
use winit::event_loop::ControlFlow;
|
||
use winit::event_loop::EventLoop;
|
||
use winit::event_loop::OwnedDisplayHandle;
|
||
use winit::window::Window;
|
||
use winit::window::WindowId;
|
||
|
||
use crate::camera::Camera;
|
||
use crate::egui_renderer::EguiRenderer;
|
||
use crate::producers::ChunkedProducer;
|
||
use crate::producers::SineGenerator;
|
||
use crate::producers::TerrainGenerator;
|
||
use crate::sparse_tree::NTreeNodeLocator;
|
||
use crate::voxel_cache::VoxelCache;
|
||
use crate::voxel_cache::data::CacheNodeRequest;
|
||
use crate::voxel_cache::data::CacheResponse;
|
||
use crate::voxel_cache::data::ColorBytes;
|
||
use crate::voxel_cache::data::DestinationElement;
|
||
use crate::voxel_cache::data::LocationPoolElement;
|
||
|
||
mod camera;
|
||
mod egui_renderer;
|
||
mod producers;
|
||
mod sparse_tree;
|
||
mod voxel_cache;
|
||
//
|
||
|
||
struct State
|
||
{
|
||
instance: wgpu::Instance,
|
||
window: Arc<Window>,
|
||
device: wgpu::Device,
|
||
queue: wgpu::Queue,
|
||
size: winit::dpi::PhysicalSize<u32>,
|
||
surface: wgpu::Surface<'static>,
|
||
depth_buffer: (wgpu::Texture, wgpu::TextureView),
|
||
surface_format: wgpu::TextureFormat,
|
||
egui_renderer: EguiRenderer,
|
||
|
||
pipeline: RenderPipeline,
|
||
voxel_cache: Arc<Mutex<VoxelCache<4>>>,
|
||
terrain_generator: Arc<TerrainGenerator<4>>,
|
||
chunk_pos_map: Arc<HashMap<u32, (usize, usize, usize)>>,
|
||
instance_buffer: Buffer,
|
||
instance_count: usize,
|
||
usage_vec: Arc<Mutex<Vec<usize>>>,
|
||
rm_time: Arc<Mutex<f32>>,
|
||
insertion_debounce: bool,
|
||
|
||
camera: Camera,
|
||
}
|
||
|
||
pub unsafe fn as_raw_bytes<T: Sized>(slice: &[T]) -> &[u8]
|
||
{
|
||
let size = slice.len() * size_of::<T>();
|
||
unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const u8, size) }
|
||
}
|
||
|
||
#[derive(Clone, Copy)]
|
||
struct Immediates
|
||
{
|
||
view_proj: Mat4,
|
||
cam_pos: Vec3,
|
||
frame_timestamp: u32,
|
||
}
|
||
|
||
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||
#[repr(C)]
|
||
struct InstanceAttribute
|
||
{
|
||
x: f32,
|
||
y: f32,
|
||
z: f32,
|
||
id: u32,
|
||
}
|
||
|
||
impl State
|
||
{
|
||
async fn new(display: OwnedDisplayHandle, window: Arc<Window>) -> State
|
||
{
|
||
let instance = wgpu::Instance::new(InstanceDescriptor {
|
||
backends: wgpu::Backends::VULKAN,
|
||
display: Some(Box::new(display)),
|
||
|
||
flags: InstanceFlags::default(),
|
||
memory_budget_thresholds: MemoryBudgetThresholds::default(),
|
||
backend_options: Default::default(),
|
||
});
|
||
let adapter = instance
|
||
.request_adapter(&wgpu::RequestAdapterOptions::default())
|
||
.await
|
||
.unwrap();
|
||
let (device, queue) = adapter
|
||
.request_device(&wgpu::DeviceDescriptor {
|
||
required_features: Features::IMMEDIATES
|
||
| Features::SHADER_EARLY_DEPTH_TEST
|
||
| Features::TIMESTAMP_QUERY,
|
||
required_limits: wgpu::Limits {
|
||
max_immediate_size: 112,
|
||
max_storage_buffers_per_shader_stage: 16,
|
||
..Default::default()
|
||
},
|
||
..Default::default()
|
||
})
|
||
.await
|
||
.unwrap();
|
||
|
||
let size = window.inner_size();
|
||
|
||
let surface = instance.create_surface(window.clone()).unwrap();
|
||
let cap = surface.get_capabilities(&adapter);
|
||
let surface_format = cap.formats[0];
|
||
|
||
let egui_renderer = EguiRenderer::new(&device, surface_format, &window);
|
||
|
||
let mut voxel_cache = VoxelCache::<4>::new(200_000, device.clone(), queue.clone());
|
||
|
||
//let terrain_generator = TerrainGenerator::<4>::new(5, "vxls_height.tif", 0.2, "img.jpg");
|
||
// let terrain_generator = TerrainGenerator::<4>::new(
|
||
// 5,
|
||
// "./pointe_percee/height.tif",
|
||
// 0.2,
|
||
// "./pointe_percee/ortho.jpg",
|
||
// );
|
||
let terrain_generator = TerrainGenerator::<4>::new(
|
||
5,
|
||
"/home/albin/Documents/vxls_maps/lapiz/height.tif",
|
||
0.2,
|
||
"/home/albin/Documents/vxls_maps/lapiz/ortho.jpg",
|
||
);
|
||
|
||
let mut chunk_pos_map = HashMap::new();
|
||
let chunk_instances = (0..terrain_generator.chunk_width)
|
||
.cartesian_product(0..terrain_generator.chunk_height)
|
||
.cartesian_product(0..terrain_generator.chunk_alt)
|
||
.map(|((x, z), y)| {
|
||
let chunk_id = voxel_cache.structure_table.allocate_structure(true);
|
||
//dbg!(chunk_id);
|
||
|
||
chunk_pos_map.insert(chunk_id, (x, y, z));
|
||
InstanceAttribute {
|
||
x: x as f32,
|
||
y: y as f32,
|
||
z: z as f32,
|
||
id: chunk_id,
|
||
}
|
||
})
|
||
.collect::<Vec<_>>();
|
||
let instance_count = chunk_instances.len();
|
||
|
||
let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||
label: Some("Instance buffer"),
|
||
contents: bytemuck::cast_slice(chunk_instances.as_slice()),
|
||
usage: BufferUsages::COPY_DST | BufferUsages::VERTEX,
|
||
});
|
||
|
||
let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||
label: Some("Main shader module"),
|
||
source: wgpu::ShaderSource::Wgsl(
|
||
std::fs::read_to_string("shaders/voxel.wgsl")
|
||
.unwrap()
|
||
.into(),
|
||
),
|
||
});
|
||
|
||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||
label: Some("Voxel pipeline layout"),
|
||
|
||
bind_group_layouts: &[Some(&voxel_cache.bind_group_layout())],
|
||
immediate_size: size_of::<Immediates>() as u32,
|
||
});
|
||
|
||
let chunk_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||
label: Some("Render pipeline"),
|
||
layout: Some(&pipeline_layout),
|
||
vertex: wgpu::VertexState {
|
||
module: &shader_module,
|
||
entry_point: Some("chunk"),
|
||
compilation_options: Default::default(),
|
||
buffers: &[Some(wgpu::VertexBufferLayout {
|
||
array_stride: (size_of::<f32>() * 3 + size_of::<u32>()) as u64,
|
||
step_mode: wgpu::VertexStepMode::Instance,
|
||
attributes: &[
|
||
wgpu::VertexAttribute {
|
||
format: wgpu::VertexFormat::Float32x3,
|
||
offset: 0,
|
||
shader_location: 0,
|
||
},
|
||
wgpu::VertexAttribute {
|
||
format: wgpu::VertexFormat::Uint32,
|
||
offset: (size_of::<f32>() * 3) as u64,
|
||
shader_location: 1,
|
||
},
|
||
],
|
||
})],
|
||
},
|
||
primitive: wgpu::PrimitiveState {
|
||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||
strip_index_format: None,
|
||
front_face: wgpu::FrontFace::Ccw,
|
||
cull_mode: Some(wgpu::Face::Front),
|
||
unclipped_depth: false,
|
||
polygon_mode: wgpu::PolygonMode::Fill,
|
||
conservative: false,
|
||
},
|
||
depth_stencil: Some(wgpu::DepthStencilState {
|
||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||
depth_write_enabled: Some(true),
|
||
depth_compare: Some(wgpu::CompareFunction::Less),
|
||
stencil: wgpu::StencilState::default(),
|
||
bias: wgpu::DepthBiasState::default(),
|
||
}),
|
||
multisample: wgpu::MultisampleState::default(),
|
||
fragment: Some(wgpu::FragmentState {
|
||
module: &shader_module,
|
||
entry_point: Some("fragment"),
|
||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||
targets: &[Some(wgpu::ColorTargetState {
|
||
format: surface_format,
|
||
blend: None,
|
||
write_mask: wgpu::ColorWrites::default(),
|
||
})],
|
||
}),
|
||
multiview_mask: None,
|
||
cache: None,
|
||
});
|
||
|
||
let state = State {
|
||
instance,
|
||
window,
|
||
size,
|
||
surface,
|
||
surface_format,
|
||
egui_renderer,
|
||
depth_buffer: Self::create_depth_buffer(&device, size.width, size.height),
|
||
queue,
|
||
device,
|
||
usage_vec: Arc::new(Mutex::new(vec![])),
|
||
pipeline: chunk_pipeline,
|
||
voxel_cache: Arc::new(Mutex::new(voxel_cache)),
|
||
insertion_debounce: false,
|
||
camera: Default::default(),
|
||
instance_buffer,
|
||
instance_count,
|
||
terrain_generator: Arc::new(terrain_generator),
|
||
chunk_pos_map: chunk_pos_map.into(),
|
||
rm_time: Arc::new(Mutex::new(0.)),
|
||
};
|
||
|
||
// Configure surface for the first time
|
||
state.configure_surface();
|
||
|
||
state
|
||
}
|
||
|
||
fn get_window(&self) -> &Window
|
||
{
|
||
&self.window
|
||
}
|
||
|
||
fn handle_event(&mut self, event: &WindowEvent)
|
||
{
|
||
self.egui_renderer.handle_input(&self.window, event);
|
||
self.camera.handle_input(event);
|
||
}
|
||
|
||
fn handle_device_event(&mut self, event: &DeviceEvent)
|
||
{
|
||
#[allow(clippy::single_match)]
|
||
match event
|
||
{
|
||
winit::event::DeviceEvent::MouseMotion { delta } =>
|
||
{
|
||
self.camera.cursor_moved(delta.0 as f32, delta.1 as f32);
|
||
}
|
||
|
||
_ =>
|
||
{}
|
||
}
|
||
}
|
||
|
||
fn create_depth_buffer(device: &Device, width: u32, height: u32) -> (Texture, TextureView)
|
||
{
|
||
let texture = device.create_texture(&wgpu::wgt::TextureDescriptor {
|
||
label: Some("Depth buffer"),
|
||
size: Extent3d {
|
||
width,
|
||
height,
|
||
depth_or_array_layers: 1,
|
||
},
|
||
mip_level_count: 1,
|
||
sample_count: 1,
|
||
dimension: wgpu::TextureDimension::D2,
|
||
format: wgpu::TextureFormat::Depth24PlusStencil8,
|
||
usage: TextureUsages::RENDER_ATTACHMENT,
|
||
view_formats: &[wgpu::TextureFormat::Depth24PlusStencil8.add_srgb_suffix()],
|
||
});
|
||
let texture_view = texture.create_view(&wgpu::wgt::TextureViewDescriptor {
|
||
label: Some("depth view"),
|
||
..Default::default()
|
||
});
|
||
(texture, texture_view)
|
||
}
|
||
|
||
fn configure_surface(&self)
|
||
{
|
||
let surface_config = wgpu::SurfaceConfiguration {
|
||
color_space: wgpu::SurfaceColorSpace::Auto,
|
||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||
format: self.surface_format,
|
||
// Request compatibility with the sRGB-format texture view we‘re going to create later.
|
||
view_formats: vec![self.surface_format.add_srgb_suffix()],
|
||
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
||
width: self.size.width,
|
||
height: self.size.height,
|
||
desired_maximum_frame_latency: 2,
|
||
present_mode: wgpu::PresentMode::AutoVsync,
|
||
};
|
||
self.surface.configure(&self.device, &surface_config);
|
||
}
|
||
|
||
fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>)
|
||
{
|
||
self.size = new_size;
|
||
self.camera.aspect = new_size.width as f32 / new_size.height as f32;
|
||
|
||
// reconfigure the surface
|
||
self.configure_surface();
|
||
self.depth_buffer =
|
||
Self::create_depth_buffer(&self.device, new_size.width, new_size.height);
|
||
}
|
||
|
||
fn render(&mut self)
|
||
{
|
||
self.camera.update();
|
||
self.voxel_cache.lock().next_frame();
|
||
|
||
// Create texture view.
|
||
// NOTE: We must handle Timeout because the surface may be unavailable
|
||
// (e.g., when the window is occluded on macOS).
|
||
let surface_texture = match self.surface.get_current_texture()
|
||
{
|
||
wgpu::CurrentSurfaceTexture::Success(texture) => texture,
|
||
wgpu::CurrentSurfaceTexture::Occluded | wgpu::CurrentSurfaceTexture::Timeout => return,
|
||
wgpu::CurrentSurfaceTexture::Suboptimal(texture) =>
|
||
{
|
||
drop(texture);
|
||
self.configure_surface();
|
||
return;
|
||
}
|
||
wgpu::CurrentSurfaceTexture::Outdated =>
|
||
{
|
||
self.configure_surface();
|
||
return;
|
||
}
|
||
wgpu::CurrentSurfaceTexture::Validation =>
|
||
{
|
||
unreachable!("No error scope registered, so validation errors will panic")
|
||
}
|
||
wgpu::CurrentSurfaceTexture::Lost =>
|
||
{
|
||
self.surface = self.instance.create_surface(self.window.clone()).unwrap();
|
||
self.configure_surface();
|
||
return;
|
||
}
|
||
};
|
||
|
||
let timestamp_query = self.device.create_query_set(&wgpu::QuerySetDescriptor {
|
||
label: Some("timestamp_query_set"),
|
||
ty: wgpu::QueryType::Timestamp,
|
||
count: 2,
|
||
});
|
||
|
||
let timestamp_buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
|
||
label: Some("timestamp_buffer"),
|
||
size: (size_of::<u64>() * 2) as u64,
|
||
usage: BufferUsages::QUERY_RESOLVE | BufferUsages::COPY_SRC,
|
||
mapped_at_creation: false,
|
||
});
|
||
|
||
let texture_view = surface_texture
|
||
.texture
|
||
.create_view(&wgpu::TextureViewDescriptor {
|
||
// Without add_srgb_suffix() the image we will be working with
|
||
// might not be "gamma correct".
|
||
format: Some(self.surface_format.add_srgb_suffix()),
|
||
..Default::default()
|
||
});
|
||
|
||
// Renders a GREEN screen
|
||
let mut encoder = self.device.create_command_encoder(&Default::default());
|
||
|
||
{
|
||
let mut renderpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||
label: None,
|
||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||
view: &texture_view,
|
||
depth_slice: None,
|
||
resolve_target: None,
|
||
ops: wgpu::Operations {
|
||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||
store: wgpu::StoreOp::Store,
|
||
},
|
||
})],
|
||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||
view: &self.depth_buffer.1,
|
||
depth_ops: Some(Operations {
|
||
load: wgpu::LoadOp::Clear(1.),
|
||
store: wgpu::StoreOp::Discard,
|
||
}),
|
||
stencil_ops: None,
|
||
}),
|
||
timestamp_writes: Some(wgpu::RenderPassTimestampWrites {
|
||
query_set: ×tamp_query,
|
||
beginning_of_pass_write_index: Some(0),
|
||
end_of_pass_write_index: Some(1),
|
||
}),
|
||
occlusion_query_set: None,
|
||
multiview_mask: None,
|
||
});
|
||
|
||
renderpass.set_pipeline(&self.pipeline);
|
||
renderpass.set_vertex_buffer(0, self.instance_buffer.slice(..));
|
||
renderpass.set_bind_group(0, Some(&self.voxel_cache.lock().bind_group()), &[]);
|
||
let imm = [Immediates {
|
||
view_proj: self.camera.view_proj(),
|
||
cam_pos: self.camera.position,
|
||
frame_timestamp: self.voxel_cache.lock().current_timestamp(),
|
||
}];
|
||
renderpass.set_immediates(0, unsafe { as_raw_bytes(&imm) });
|
||
renderpass.draw(0..36, 0..(self.instance_count as u32));
|
||
|
||
// End the renderpass.
|
||
drop(renderpass);
|
||
|
||
encoder.resolve_query_set(×tamp_query, 0..2, ×tamp_buffer, 0);
|
||
}
|
||
|
||
let requests = self.device.create_buffer(&wgpu::BufferDescriptor {
|
||
label: Some("dummy_dumb_dinky_aaaahhh_buffer"),
|
||
size: 16 * 2000,
|
||
usage: BufferUsages::STORAGE | BufferUsages::COPY_SRC,
|
||
mapped_at_creation: false,
|
||
});
|
||
|
||
if !self
|
||
.camera
|
||
.pressed_keyset
|
||
.contains(&winit::keyboard::KeyCode::KeyF)
|
||
{
|
||
self.voxel_cache
|
||
.lock()
|
||
.cache_post_render(&mut encoder, requests.clone());
|
||
}
|
||
|
||
// If you wanted to call any drawing commands, they would go here.
|
||
{
|
||
self.egui_renderer.begin_frame(&self.window);
|
||
egui::Window::new("Window ! ").resizable(true).show(
|
||
self.egui_renderer.context(),
|
||
|ui| {
|
||
if self
|
||
.camera
|
||
.pressed_keyset
|
||
.contains(&winit::keyboard::KeyCode::KeyF)
|
||
{
|
||
ui.label(
|
||
egui::RichText::new("Cache paused")
|
||
.color(Color32::RED)
|
||
.size(28.),
|
||
);
|
||
}
|
||
|
||
ui.label(format!(
|
||
"Ray-marching time: {}",
|
||
*self.rm_time.lock() / 1_000_000.
|
||
));
|
||
egui_plot::Plot::new("Plot").show(ui, |plot_ui| {
|
||
plot_ui.bar_chart(BarChart::new(
|
||
"histo",
|
||
self.usage_vec
|
||
.lock()
|
||
.iter()
|
||
.enumerate()
|
||
.map(|(i, x)| egui_plot::Bar::new(i as f64, *x as f64))
|
||
.collect(),
|
||
));
|
||
});
|
||
ui.label("Hello !")
|
||
},
|
||
);
|
||
|
||
let screen_descriptor = egui_wgpu::ScreenDescriptor {
|
||
size_in_pixels: [self.size.width, self.size.height],
|
||
pixels_per_point: self.window.as_ref().scale_factor() as f32,
|
||
};
|
||
|
||
self.egui_renderer.end_frame_and_draw(
|
||
&self.device,
|
||
&self.queue,
|
||
&mut encoder,
|
||
&self.window,
|
||
&texture_view,
|
||
screen_descriptor,
|
||
);
|
||
}
|
||
|
||
// Report usage
|
||
let time_stamp = self.voxel_cache.lock().current_timestamp();
|
||
let cloned_usage_histogram = self.usage_vec.clone();
|
||
DownloadBuffer::read_buffer(
|
||
&self.device,
|
||
&self.queue,
|
||
&self.voxel_cache.lock().usage_buffer.usage_buffer.slice(..),
|
||
move |slice| {
|
||
let slice = slice.unwrap();
|
||
let cache_slice: &[u32] = bytemuck::cast_slice(&slice);
|
||
let mut v = vec![0; 100];
|
||
for x in cache_slice.iter()
|
||
{
|
||
let diff = (time_stamp - x).min(99);
|
||
v[diff as usize] += 1;
|
||
}
|
||
*cloned_usage_histogram.lock() = v;
|
||
},
|
||
);
|
||
|
||
// Submit the command in the queue to execute
|
||
self.queue.submit([encoder.finish()]);
|
||
self.window.pre_present_notify();
|
||
self.queue.present(surface_texture);
|
||
if !self
|
||
.camera
|
||
.pressed_keyset
|
||
.contains(&winit::keyboard::KeyCode::KeyF)
|
||
&& self.insertion_debounce
|
||
{
|
||
self.insertion_debounce = false;
|
||
}
|
||
|
||
// if (self
|
||
// .camera
|
||
// .pressed_keyset
|
||
// .contains(&winit::keyboard::KeyCode::KeyF))
|
||
// && !self.insertion_debounce
|
||
// {
|
||
|
||
// Report frame time
|
||
let cloned_rm_time = self.rm_time.clone();
|
||
let cloned_queue = self.queue.clone();
|
||
DownloadBuffer::read_buffer(
|
||
&self.device,
|
||
&self.queue,
|
||
×tamp_buffer.slice(..),
|
||
move |buffer| {
|
||
let buffer_slice = buffer.unwrap();
|
||
let slice: &[u64] = cast_slice(&buffer_slice);
|
||
let time = (slice[1] - slice[0]) as f32 * cloned_queue.get_timestamp_period();
|
||
*cloned_rm_time.lock() = time;
|
||
},
|
||
);
|
||
|
||
if !self
|
||
.camera
|
||
.pressed_keyset
|
||
.contains(&winit::keyboard::KeyCode::KeyF)
|
||
{
|
||
self.insertion_debounce = true;
|
||
let request_count = self.voxel_cache.lock().total_request_count();
|
||
let cloned_cache = self.voxel_cache.clone();
|
||
let cloned_device = self.device.clone();
|
||
let cloned_queue = self.queue.clone();
|
||
let cloned_generator = self.terrain_generator.clone();
|
||
let cloned_map = self.chunk_pos_map.clone();
|
||
let (tx, rx) = sync_channel(1);
|
||
DownloadBuffer::read_buffer(
|
||
&self.device.clone(),
|
||
&self.queue.clone(),
|
||
&requests.slice(0..),
|
||
move |buffer| {
|
||
if tx.try_send(()).is_err()
|
||
{
|
||
return;
|
||
}
|
||
|
||
let cache_node_requests: Vec<CacheNodeRequest> =
|
||
bytemuck::pod_collect_to_vec(&buffer.unwrap());
|
||
|
||
let generator = cloned_generator;
|
||
let gen_test = SineGenerator::<4>::new(5);
|
||
|
||
let mut structure_nodes = vec![];
|
||
let mut color_nodes: Vec<[ColorBytes; 64]> = vec![];
|
||
let mut location_nodes = vec![];
|
||
let mut destinations = vec![];
|
||
|
||
cache_node_requests
|
||
.par_iter()
|
||
.take(request_count as usize)
|
||
.map(|request| {
|
||
// Unpack structure id
|
||
let (chunk_x, chunk_y, chunk_z) =
|
||
*cloned_map.get(&request.structure_id).unwrap();
|
||
|
||
let location;
|
||
let node;
|
||
if request.child_index == u32::MAX
|
||
{
|
||
// Produce root node
|
||
node =
|
||
generator.produce_node(0, 0, 0, 0, (chunk_x, chunk_y, chunk_z));
|
||
location = LocationPoolElement {
|
||
structure_id: request.structure_id,
|
||
structure_locator: NTreeNodeLocator::<4>::root().as_usize()
|
||
as u32,
|
||
};
|
||
}
|
||
else
|
||
{
|
||
// Figure out depth of request
|
||
let locator = NTreeNodeLocator::<4>::from_usize(
|
||
request.structure_locator as usize,
|
||
);
|
||
let depth = locator.depth();
|
||
//let (x, y, z) = locator.node_location();
|
||
|
||
let child_z = request.child_index / (4 * 4);
|
||
let child_y = (request.child_index % (4 * 4)) / 4;
|
||
let child_x = request.child_index % 4;
|
||
|
||
let child_locator = locator.child(
|
||
child_x as usize,
|
||
child_y as usize,
|
||
child_z as usize,
|
||
);
|
||
|
||
let (nx, ny, nz) = child_locator.node_location();
|
||
|
||
node = generator.produce_node(
|
||
depth + 1,
|
||
nx,
|
||
ny,
|
||
nz,
|
||
(chunk_x, chunk_y, chunk_z),
|
||
);
|
||
|
||
location = LocationPoolElement {
|
||
structure_id: request.structure_id,
|
||
structure_locator: child_locator.as_usize() as u32,
|
||
};
|
||
}
|
||
|
||
(
|
||
node.structure,
|
||
node.colors,
|
||
location,
|
||
DestinationElement {
|
||
node: request.node_index,
|
||
child: request.child_index,
|
||
},
|
||
)
|
||
})
|
||
.collect::<Vec<_>>()
|
||
.into_iter()
|
||
.for_each(|data| {
|
||
structure_nodes.push(data.0);
|
||
color_nodes.push(std::array::from_fn(|i| data.1[i].into()));
|
||
location_nodes.push(data.2);
|
||
destinations.push(data.3);
|
||
});
|
||
|
||
if structure_nodes.len() != 0
|
||
{
|
||
let structre_node_buffer =
|
||
cloned_device.create_buffer_init(&BufferInitDescriptor {
|
||
label: None,
|
||
contents: unsafe { as_raw_bytes(structure_nodes.as_slice()) },
|
||
usage: BufferUsages::STORAGE,
|
||
});
|
||
let color_node_buffer =
|
||
cloned_device.create_buffer_init(&BufferInitDescriptor {
|
||
label: None,
|
||
contents: unsafe { as_raw_bytes(color_nodes.as_slice()) },
|
||
usage: BufferUsages::STORAGE,
|
||
});
|
||
let location_node_buffer =
|
||
cloned_device.create_buffer_init(&BufferInitDescriptor {
|
||
label: None,
|
||
contents: unsafe { as_raw_bytes(location_nodes.as_slice()) },
|
||
usage: BufferUsages::STORAGE,
|
||
});
|
||
let destinations_buffer =
|
||
cloned_device.create_buffer_init(&BufferInitDescriptor {
|
||
label: None,
|
||
contents: unsafe { as_raw_bytes(destinations.as_slice()) },
|
||
usage: BufferUsages::STORAGE,
|
||
});
|
||
|
||
let mut encoder = cloned_device.create_command_encoder(&Default::default());
|
||
cloned_cache.lock().cache_insert(
|
||
&mut encoder,
|
||
&CacheResponse {
|
||
structure_nodes: structre_node_buffer,
|
||
color_nodes: color_node_buffer,
|
||
locations: location_node_buffer,
|
||
parents: destinations_buffer,
|
||
},
|
||
);
|
||
cloned_queue.submit([encoder.finish()]);
|
||
}
|
||
},
|
||
);
|
||
//println!("Total request count: {}", request_count);
|
||
loop
|
||
{
|
||
if rx.try_recv().is_ok()
|
||
{
|
||
break;
|
||
}
|
||
let _ = self.device.poll(wgpu::wgt::PollType::Poll);
|
||
}
|
||
|
||
drop(rx);
|
||
}
|
||
}
|
||
|
||
pub fn mouse_wheel(&mut self, delta: MouseScrollDelta)
|
||
{
|
||
if let MouseScrollDelta::LineDelta(_, y) = delta
|
||
{
|
||
self.camera.speed += y * (self.camera.speed * 0.05);
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Default)]
|
||
struct App
|
||
{
|
||
state: Option<State>,
|
||
}
|
||
|
||
impl ApplicationHandler for App
|
||
{
|
||
fn resumed(&mut self, event_loop: &ActiveEventLoop)
|
||
{
|
||
// Create window object
|
||
let window = Arc::new(
|
||
event_loop
|
||
.create_window(Window::default_attributes())
|
||
.unwrap(),
|
||
);
|
||
|
||
let state = pollster::block_on(State::new(
|
||
event_loop.owned_display_handle(),
|
||
window.clone(),
|
||
));
|
||
self.state = Some(state);
|
||
|
||
window.request_redraw();
|
||
window.set_cursor_visible(false);
|
||
// window
|
||
// .set_cursor_grab(winit::window::CursorGrabMode::Locked)
|
||
// .unwrap();
|
||
let _ = window
|
||
.set_cursor_grab(winit::window::CursorGrabMode::Locked)
|
||
.or_else(|_| window.set_cursor_grab(winit::window::CursorGrabMode::Confined));
|
||
}
|
||
|
||
fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent)
|
||
{
|
||
let state = self.state.as_mut().unwrap();
|
||
state.handle_event(&event);
|
||
match event
|
||
{
|
||
WindowEvent::CloseRequested =>
|
||
{
|
||
println!("The close button was pressed; stopping");
|
||
event_loop.exit();
|
||
}
|
||
WindowEvent::RedrawRequested =>
|
||
{
|
||
state.render();
|
||
// Emits a new redraw requested event.
|
||
state.get_window().request_redraw();
|
||
}
|
||
WindowEvent::Resized(size) =>
|
||
{
|
||
// Reconfigures the size of the surface. We do not re-render
|
||
// here as this event is always followed up by redraw request.
|
||
state.resize(size);
|
||
}
|
||
WindowEvent::MouseWheel { delta, .. } =>
|
||
{
|
||
state.mouse_wheel(delta);
|
||
}
|
||
|
||
_ => (),
|
||
}
|
||
}
|
||
|
||
fn device_event(
|
||
&mut self,
|
||
_event_loop: &event_loop::ActiveEventLoop,
|
||
_device_id: winit::event::DeviceId,
|
||
event: winit::event::DeviceEvent,
|
||
)
|
||
{
|
||
let state = self.state.as_mut().unwrap();
|
||
state.handle_device_event(&event);
|
||
}
|
||
}
|
||
|
||
fn main()
|
||
{
|
||
// wgpu uses `log` for all of our logging, so we initialize a logger with the `env_logger` crate.
|
||
//
|
||
// To change the log level, set the `RUST_LOG` environment variable. See the `env_logger`
|
||
// documentation for more information.
|
||
env_logger::init();
|
||
|
||
let event_loop = EventLoop::builder().build().unwrap();
|
||
//let event_loop = EventLoop::builder().with_x11().build().unwrap();
|
||
|
||
// When the current loop iteration finishes, immediately begin a new
|
||
// iteration regardless of whether or not new events are available to
|
||
// process. Preferred for applications that want to render as fast as
|
||
// possible, like games.
|
||
event_loop.set_control_flow(ControlFlow::Poll);
|
||
|
||
// When the current loop iteration finishes, suspend the thread until
|
||
// another event arrives. Helps keeping CPU utilization low if nothing
|
||
// is happening, which is preferred if the application might be idling in
|
||
// the background.
|
||
// event_loop.set_control_flow(ControlFlow::Wait);
|
||
|
||
let mut app = App::default();
|
||
event_loop.run_app(&mut app).unwrap();
|
||
}
|
||
|
||
#[derive(AsStd140)]
|
||
pub struct ChunkImmediate
|
||
{
|
||
mvp: Mat4,
|
||
eye_pos: Vec3,
|
||
root_color: Vec4,
|
||
root_subdiv: bool,
|
||
frame_timestamp: u32,
|
||
}
|