Start clean
This commit is contained in:
432
src/state.rs
Normal file
432
src/state.rs
Normal file
@ -0,0 +1,432 @@
|
||||
use std::collections::HashSet;
|
||||
use std::f32::consts::PI;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytemuck::bytes_of;
|
||||
use egui_wgpu::ScreenDescriptor;
|
||||
use gpu_shared::ChunkPushConstants;
|
||||
use wgpu::ExperimentalFeatures;
|
||||
use wgpu::Extent3d;
|
||||
use wgpu::Features;
|
||||
use wgpu::FeaturesWGPU;
|
||||
use wgpu::FeaturesWebGPU;
|
||||
use wgpu::RenderPipeline;
|
||||
use wgpu::ShaderStages;
|
||||
use wgpu::TextureDescriptor;
|
||||
use wgpu::TextureFormat;
|
||||
use wgpu::TextureUsages;
|
||||
use wgpu::TextureView;
|
||||
use wgpu::include_spirv;
|
||||
use wgpu::include_spirv_raw;
|
||||
use winit::event::MouseScrollDelta;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::keyboard::KeyCode;
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::egui_renderer::EguiState;
|
||||
|
||||
pub struct State
|
||||
{
|
||||
window: Arc<Window>,
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
size: winit::dpi::PhysicalSize<u32>,
|
||||
surface: wgpu::Surface<'static>,
|
||||
surface_format: wgpu::TextureFormat,
|
||||
egui_state: EguiState,
|
||||
|
||||
// Camera
|
||||
camera: Camera,
|
||||
|
||||
// pressed events
|
||||
pressed_set: HashSet<KeyCode>,
|
||||
pipeline: RenderPipeline,
|
||||
depth_buffer: TextureView,
|
||||
}
|
||||
|
||||
impl State
|
||||
{
|
||||
pub async fn new(window: Arc<Window>) -> State
|
||||
{
|
||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
|
||||
let adapter = instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let (device, queue) = adapter
|
||||
.request_device(&wgpu::DeviceDescriptor {
|
||||
required_features: Features {
|
||||
features_wgpu: FeaturesWGPU::PUSH_CONSTANTS
|
||||
| FeaturesWGPU::EXPERIMENTAL_PASSTHROUGH_SHADERS,
|
||||
features_webgpu: FeaturesWebGPU::empty(),
|
||||
},
|
||||
experimental_features: unsafe { ExperimentalFeatures::enabled() },
|
||||
required_limits: wgpu::Limits {
|
||||
max_push_constant_size: size_of::<ChunkPushConstants>() as u32,
|
||||
..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 shaders = include_spirv!(env!("shaders.spv"));
|
||||
// let shader_module = device.create_shader_module(shaders);
|
||||
let shaders = include_spirv_raw!(env!("shaders.spv"));
|
||||
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("chunk_pipeline"),
|
||||
layout: Some(
|
||||
&device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: None,
|
||||
bind_group_layouts: &[],
|
||||
push_constant_ranges: &[wgpu::PushConstantRange {
|
||||
stages: wgpu::ShaderStages::VERTEX,
|
||||
range: 0..(size_of::<ChunkPushConstants>() as u32),
|
||||
}],
|
||||
}),
|
||||
),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader_module,
|
||||
entry_point: Some("main_vs"),
|
||||
buffers: &[],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader_module,
|
||||
entry_point: Some("main_fs"),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: surface_format,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: TextureFormat::Depth24PlusStencil8,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil: wgpu::StencilState::default(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
|
||||
cache: None,
|
||||
});
|
||||
|
||||
let state = State {
|
||||
egui_state: EguiState::new(&device, surface_format, &window),
|
||||
|
||||
camera: Camera {
|
||||
eye: glam::Vec3::new(0., 0., 0.),
|
||||
up: glam::Vec3::ZERO.with_y(1.),
|
||||
aspect: size.width as f32 / size.height as f32,
|
||||
fovy: 90.,
|
||||
znear: 0.001,
|
||||
zfar: 1000.,
|
||||
radius: 2.,
|
||||
yaw: 1.,
|
||||
pitch: 0.,
|
||||
rotation_speed: 0.005,
|
||||
speed: 0.005,
|
||||
},
|
||||
|
||||
window,
|
||||
queue,
|
||||
size,
|
||||
surface,
|
||||
surface_format,
|
||||
pipeline,
|
||||
pressed_set: HashSet::new(),
|
||||
depth_buffer: device
|
||||
.create_texture(&TextureDescriptor {
|
||||
label: Some("Depth buffer"),
|
||||
size: Extent3d {
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: TextureFormat::Depth24PlusStencil8,
|
||||
usage: TextureUsages::RENDER_ATTACHMENT,
|
||||
view_formats: &[],
|
||||
})
|
||||
.create_view(&Default::default()),
|
||||
|
||||
device,
|
||||
};
|
||||
|
||||
// Configure surface for the first time
|
||||
state.configure_surface();
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
pub fn get_window(&self) -> &Window
|
||||
{
|
||||
&self.window
|
||||
}
|
||||
|
||||
pub fn configure_surface(&self)
|
||||
{
|
||||
let surface_config = wgpu::SurfaceConfiguration {
|
||||
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);
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>)
|
||||
{
|
||||
self.size = new_size;
|
||||
|
||||
// reconfigure the surface
|
||||
self.configure_surface();
|
||||
|
||||
self.depth_buffer = self
|
||||
.device
|
||||
.create_texture(&TextureDescriptor {
|
||||
label: Some("Depth buffer"),
|
||||
size: Extent3d {
|
||||
width: new_size.width,
|
||||
height: new_size.height,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: TextureFormat::Depth24PlusStencil8,
|
||||
usage: TextureUsages::RENDER_ATTACHMENT,
|
||||
view_formats: &[],
|
||||
})
|
||||
.create_view(&Default::default());
|
||||
}
|
||||
|
||||
pub fn render(&mut self)
|
||||
{
|
||||
self.update_camera();
|
||||
|
||||
// Create texture view
|
||||
let surface_texture = self
|
||||
.surface
|
||||
.get_current_texture()
|
||||
.expect("failed to acquire next swapchain texture");
|
||||
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 {
|
||||
r: 0.01,
|
||||
g: 0.01,
|
||||
b: 0.01,
|
||||
a: 1.,
|
||||
}),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||
view: &self.depth_buffer,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.),
|
||||
store: wgpu::StoreOp::Discard,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
renderpass.set_pipeline(&self.pipeline);
|
||||
renderpass.set_push_constants(
|
||||
ShaderStages::VERTEX,
|
||||
0,
|
||||
bytes_of(&ChunkPushConstants {
|
||||
view_projection: self.camera.view_proj(),
|
||||
transform: glam::Mat4::IDENTITY,
|
||||
eye_position: self.camera.eye,
|
||||
_zero_pad: 0.,
|
||||
}),
|
||||
);
|
||||
renderpass.draw(0..36, 0..1);
|
||||
|
||||
// End the renderpass.
|
||||
}
|
||||
// Egui
|
||||
{
|
||||
let screen_descriptor = ScreenDescriptor {
|
||||
size_in_pixels: [self.size.width, self.size.height],
|
||||
pixels_per_point: 1.,
|
||||
};
|
||||
self.egui_state.begin_frame(&self.window);
|
||||
|
||||
egui::Window::new("Hello Window").resizable(true).show(
|
||||
self.egui_state.context(),
|
||||
|ui| {
|
||||
ui.label("Hello, world.");
|
||||
},
|
||||
);
|
||||
|
||||
self.egui_state.end_frame_and_draw(
|
||||
&self.device,
|
||||
&self.queue,
|
||||
&mut encoder,
|
||||
&self.window,
|
||||
&texture_view,
|
||||
screen_descriptor,
|
||||
);
|
||||
}
|
||||
|
||||
// Submit the command in the queue to execute
|
||||
self.queue.submit([encoder.finish()]);
|
||||
self.window.pre_present_notify();
|
||||
surface_texture.present();
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// MOVEMENT
|
||||
// ------------------------------
|
||||
pub fn handle_event(&mut self, event: &WindowEvent)
|
||||
{
|
||||
self.egui_state.handle_event(&self.window, event);
|
||||
|
||||
if let WindowEvent::KeyboardInput { event, .. } = event
|
||||
{
|
||||
match (event.state, event.physical_key)
|
||||
{
|
||||
(winit::event::ElementState::Pressed, winit::keyboard::PhysicalKey::Code(c)) =>
|
||||
{
|
||||
self.pressed_set.insert(c);
|
||||
}
|
||||
(winit::event::ElementState::Released, winit::keyboard::PhysicalKey::Code(c)) =>
|
||||
{
|
||||
self.pressed_set.remove(&c);
|
||||
}
|
||||
_ =>
|
||||
{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_camera(&mut self)
|
||||
{
|
||||
let mut movement = glam::Vec3::new(0., 0., 0.);
|
||||
if self.pressed_set.contains(&KeyCode::KeyW)
|
||||
{
|
||||
movement.z += self.camera.speed;
|
||||
}
|
||||
if self.pressed_set.contains(&KeyCode::KeyS)
|
||||
{
|
||||
movement.z -= self.camera.speed;
|
||||
}
|
||||
|
||||
// Left rigth
|
||||
if self.pressed_set.contains(&KeyCode::KeyA)
|
||||
{
|
||||
movement.x += self.camera.speed;
|
||||
}
|
||||
if self.pressed_set.contains(&KeyCode::KeyD)
|
||||
{
|
||||
movement.x -= self.camera.speed;
|
||||
}
|
||||
|
||||
let rot_movement = glam::Mat3::from_rotation_y(-self.camera.yaw)
|
||||
* glam::Mat3::from_rotation_x(-self.camera.pitch)
|
||||
* movement;
|
||||
self.camera.eye -= rot_movement;
|
||||
}
|
||||
|
||||
pub fn cursor_moved(&mut self, x: f32, y: f32)
|
||||
{
|
||||
const SENSIBILITY: f32 = 0.0004;
|
||||
let position = glam::Vec2::new(x, y);
|
||||
let offset = position * SENSIBILITY;
|
||||
|
||||
self.camera.yaw += offset.x;
|
||||
self.camera.pitch += offset.y;
|
||||
}
|
||||
|
||||
pub fn mouse_wheel(&mut self, delta: MouseScrollDelta)
|
||||
{
|
||||
if let MouseScrollDelta::LineDelta(_, y) = delta
|
||||
{
|
||||
self.camera.speed += y * (self.camera.speed * 0.05);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Camera
|
||||
{
|
||||
pub eye: glam::Vec3,
|
||||
pub up: glam::Vec3,
|
||||
pub aspect: f32,
|
||||
pub fovy: f32,
|
||||
pub znear: f32,
|
||||
pub zfar: f32,
|
||||
|
||||
pub radius: f32,
|
||||
|
||||
pub yaw: f32,
|
||||
pub pitch: f32,
|
||||
pub rotation_speed: f32,
|
||||
pub speed: f32,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const OPENGL_TO_WGPU_MATRIX: glam::Mat4 = glam::Mat4::from_cols(
|
||||
glam::Vec4::new(1.0, 0.0, 0.0, 0.0),
|
||||
glam::Vec4::new(0.0, 1.0, 0.0, 0.0),
|
||||
glam::Vec4::new(0.0, 0.0, 0.5, 0.0),
|
||||
glam::Vec4::new(0.0, 0.0, 0.5, 1.0),
|
||||
);
|
||||
|
||||
impl Camera
|
||||
{
|
||||
pub fn view_proj(&self) -> glam::Mat4
|
||||
{
|
||||
let view = glam::Mat4::from_translation(self.eye)
|
||||
* glam::Mat4::from_rotation_y(-self.yaw)
|
||||
* glam::Mat4::from_rotation_x(-self.pitch);
|
||||
let proj =
|
||||
glam::Mat4::perspective_rh(PI * self.fovy / 180., self.aspect, self.znear, self.zfar);
|
||||
proj * view.inverse()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user