diff --git a/Cargo.lock b/Cargo.lock index e3458f75..593b67ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -873,7 +873,6 @@ dependencies = [ "oddio", "ordered-float", "profiling", - "raw-window-handle", "rayon", "serde", "slotmapd", diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 0a0baceb..e32e1910 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -19,7 +19,6 @@ wgpu = { version = "0.18.0", default-features = false, features=["wgsl" bytemuck = "1.7.2" image = { version = "0.24.3", default-features = false, features = ["png"] } log = "0.4.11" -raw-window-handle = "0.5.0" gltf = { version = "1.2.0", default-features=false, features=["import", "utils", "names"] } itertools = { version = "0.11.0", default-features = false } profiling = { version = "1.0.1", default-features = false } diff --git a/engine/src/egui.rs b/engine/src/egui.rs index b55ea26d..b1e5690a 100644 --- a/engine/src/egui.rs +++ b/engine/src/egui.rs @@ -3,7 +3,6 @@ use egui::TextureId; use egui_wgpu::renderer; use egui_wgpu::renderer::ScreenDescriptor; use winit::event_loop::EventLoopWindowTarget; -use winit::window::Window; /// EguiWrapper is a wrapper around egui and egui_wgpu /// It handles the rendering of the UI @@ -40,14 +39,13 @@ impl EguiWrapper { pub fn render( &mut self, gfx: GuiRenderContext<'_, '_>, - window: &Window, ui_render: impl for<'ui> FnOnce(&'ui egui::Context), ) { for id in self.to_remove.drain(..) { self.renderer.free_texture(&id); } - let rinput = self.platform.take_egui_input(window); + let rinput = self.platform.take_egui_input(gfx.window); self.egui.set_zoom_factor(self.zoom_factor); let output = self.egui.run(rinput, |ctx| { @@ -97,7 +95,7 @@ impl EguiWrapper { //} self.platform - .handle_platform_output(window, &self.egui, output.platform_output); + .handle_platform_output(gfx.window, &self.egui, output.platform_output); self.last_mouse_captured = self.egui.wants_pointer_input(); self.last_kb_captured = self.egui.wants_keyboard_input(); diff --git a/engine/src/framework.rs b/engine/src/framework.rs index 6a4c288b..7bdc6d9d 100644 --- a/engine/src/framework.rs +++ b/engine/src/framework.rs @@ -38,7 +38,7 @@ async fn run(el: EventLoop<()>, window: Window) { ctx.gfx.defines_changed = false; let mut frame: Option> = None; - let mut scale_factor = ctx.window.scale_factor(); + let mut scale_factor = ctx.gfx.window.scale_factor(); log::info!("initial scale factor: {:?}", scale_factor); let mut new_size: Option<(PhysicalSize, f64)> = None; let mut last_update = Instant::now(); @@ -126,10 +126,9 @@ async fn run(el: EventLoop<()>, window: Window) { let (mut enc, view) = ctx.gfx.start_frame(&sco); ctx.gfx.render_objs(&mut enc, &view, |fc| state.render(fc)); - let window = &ctx.window; ctx.gfx .render_gui(&mut enc, &view, |gctx| { - ctx.egui.render(gctx, window, |ui| { + ctx.egui.render(gctx, |ui| { state.render_gui(ui); }); }); @@ -214,20 +213,13 @@ pub struct Context { pub gfx: GfxContext, pub input: InputContext, pub audio: AudioContext, - pub window: Window, pub delta: f32, pub egui: EguiWrapper, } impl Context { pub async fn new(window: Window, el: &EventLoop<()>) -> Self { - let gfx = GfxContext::new( - &window, - window.inner_size().width, - window.inner_size().height, - window.scale_factor(), - ) - .await; + let gfx = GfxContext::new(window).await; let input = InputContext::default(); let audio = AudioContext::new(); let egui = EguiWrapper::new(&gfx, el); @@ -236,7 +228,6 @@ impl Context { gfx, input, audio, - window, delta: 0.0, egui, } diff --git a/engine/src/gfx.rs b/engine/src/gfx.rs index 82c78e7e..e3ff8d06 100644 --- a/engine/src/gfx.rs +++ b/engine/src/gfx.rs @@ -6,7 +6,7 @@ use crate::{ }; use common::FastMap; use geom::{vec2, LinearColor, Matrix4, Vec2, Vec3}; -use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; +use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::collections::HashMap; use std::hash::Hash; @@ -22,6 +22,7 @@ use wgpu::{ TextureFormat, TextureUsages, TextureView, TextureViewDescriptor, TextureViewDimension, VertexBufferLayout, VertexState, }; +use winit::window::{Fullscreen, Window}; pub struct FBOs { pub(crate) depth: Texture, @@ -32,6 +33,7 @@ pub struct FBOs { } pub struct GfxContext { + pub window: Window, pub surface: Surface, pub device: Device, pub queue: Queue, @@ -39,6 +41,7 @@ pub struct GfxContext { pub size: (u32, u32, f64), pub(crate) sc_desc: SurfaceConfiguration, pub update_sc: bool, + settings: GfxSettings, pub(crate) materials: MaterialMap, pub(crate) default_material: Material, @@ -67,6 +70,75 @@ pub struct GfxContext { pub(crate) adapter: Adapter, } +#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq)] +pub enum ShadowQuality { + NoShadows, + Low, + Medium, + High, + TooHigh, +} + +impl AsRef for ShadowQuality { + fn as_ref(&self) -> &str { + match self { + ShadowQuality::NoShadows => "No Shadows", + ShadowQuality::Low => "Low", + ShadowQuality::Medium => "Medium", + ShadowQuality::High => "High", + ShadowQuality::TooHigh => "Too High", + } + } +} + +impl From for ShadowQuality { + fn from(v: u8) -> Self { + match v { + 0 => ShadowQuality::NoShadows, + 1 => ShadowQuality::Low, + 2 => ShadowQuality::Medium, + 3 => ShadowQuality::High, + 4 => ShadowQuality::TooHigh, + _ => ShadowQuality::High, + } + } +} + +impl ShadowQuality { + pub fn size(&self) -> Option { + match self { + ShadowQuality::Low => Some(512), + ShadowQuality::Medium => Some(1024), + ShadowQuality::High => Some(2048), + ShadowQuality::TooHigh => Some(4096), + ShadowQuality::NoShadows => None, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct GfxSettings { + pub vsync: bool, + pub fullscreen: bool, + pub shadows: ShadowQuality, + pub fog: bool, + pub ssao: bool, + pub terrain_grid: bool, +} + +impl Default for GfxSettings { + fn default() -> Self { + Self { + vsync: true, + fullscreen: false, + shadows: ShadowQuality::High, + fog: true, + ssao: true, + terrain_grid: true, + } + } +} + pub struct Encoders { pub pbr: Option, pub smap: Option, @@ -125,6 +197,7 @@ impl Default for RenderParams { u8slice_impl!(RenderParams); pub struct GuiRenderContext<'a, 'b> { + pub window: &'a Window, pub encoder: &'a mut CommandEncoder, pub view: &'a TextureView, pub size: (u32, u32, f64), @@ -145,12 +218,7 @@ impl<'a> FrameContext<'a> { } impl GfxContext { - pub async fn new( - window: &W, - win_width: u32, - win_height: u32, - win_scale_factor: f64, - ) -> Self { + pub async fn new(window: Window) -> Self { let mut backends = backend_bits_from_env().unwrap_or_else(Backends::all); if std::env::var("RENDERDOC").is_ok() { backends = Backends::VULKAN; @@ -163,7 +231,7 @@ impl GfxContext { gles_minor_version: wgpu::Gles3MinorVersion::Automatic, }); - let surface = unsafe { instance.create_surface(window).unwrap() }; + let surface = unsafe { instance.create_surface(&window).unwrap() }; let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, @@ -195,6 +263,10 @@ impl GfxContext { .find(|x| x.is_srgb()) .unwrap_or_else(|| &capabilities.formats[0]); + let win_width = window.inner_size().width; + let win_height = window.inner_size().height; + let win_scale_factor = window.scale_factor(); + let sc_desc = SurfaceConfiguration { usage: TextureUsages::RENDER_ATTACHMENT, format, @@ -244,6 +316,7 @@ impl GfxContext { .build(&device, &queue); let mut me = Self { + window, size: (win_width, win_height, win_scale_factor), sc_desc, update_sc: false, @@ -273,6 +346,7 @@ impl GfxContext { pbr, defines: Default::default(), defines_changed: false, + settings: GfxSettings::default(), }; me.update_simplelit_bg(); @@ -404,8 +478,20 @@ impl GfxContext { .expect("palette not loaded") } - pub fn set_vsync(&mut self, vsync: bool) { - let present_mode = if vsync { + pub fn update_settings(&mut self, settings: GfxSettings) { + if self.settings == settings { + return; + } + + if settings.fullscreen != self.settings.fullscreen { + self.window.set_fullscreen( + settings + .fullscreen + .then(|| Fullscreen::Borderless(self.window.current_monitor())), + ) + } + + let present_mode = if settings.vsync { wgpu::PresentMode::AutoVsync } else { wgpu::PresentMode::AutoNoVsync @@ -414,6 +500,22 @@ impl GfxContext { self.sc_desc.present_mode = present_mode; self.update_sc = true; } + + let params = self.render_params.value_mut(); + params.shadow_mapping_resolution = settings.shadows.size().unwrap_or(0) as i32; + + if let Some(v) = settings.shadows.size() { + if self.sun_shadowmap.extent.width != v { + self.sun_shadowmap = GfxContext::mk_shadowmap(&self.device, v); + self.update_simplelit_bg(); + } + } + + self.set_define_flag("FOG", settings.fog); + self.set_define_flag("SSAO", settings.ssao); + self.set_define_flag("TERRAIN_GRID", settings.terrain_grid); + + self.settings = settings; } pub fn set_time(&mut self, time: f32) { @@ -654,6 +756,7 @@ impl GfxContext { ) { profiling::scope!("gfx::render_gui"); render_gui(GuiRenderContext { + window: &self.window, encoder: &mut encoders.end, view: frame, size: self.size, diff --git a/engine/src/lib.rs b/engine/src/lib.rs index acdb12b1..aac198c0 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -39,6 +39,6 @@ pub use uniform::*; pub use vertex_types::*; pub use winit::event::ScanCode; -pub use winit::window::{CursorGrabMode, Fullscreen}; +pub use winit::window::CursorGrabMode; pub use wgpu; diff --git a/engine_demo/src/main.rs b/engine_demo/src/main.rs index 6c47aff9..0479e160 100644 --- a/engine_demo/src/main.rs +++ b/engine_demo/src/main.rs @@ -44,7 +44,6 @@ impl engine::framework::State for State { fn new(ctx: &mut Context) -> Self { let gfx = &mut ctx.gfx; - gfx.set_vsync(false); gfx.render_params.value_mut().shadow_mapping_resolution = 2048; gfx.sun_shadowmap = GfxContext::mk_shadowmap(&gfx.device, 2048); gfx.update_simplelit_bg(); @@ -92,20 +91,23 @@ impl engine::framework::State for State { self.ms_hist.add_value(ctx.delta); if ctx.input.mouse.pressed.contains(&MouseButton::Left) { - let _ = ctx.window.set_cursor_grab(engine::CursorGrabMode::Confined); - ctx.window.set_cursor_visible(false); + let _ = ctx + .gfx + .window + .set_cursor_grab(engine::CursorGrabMode::Confined); + ctx.gfx.window.set_cursor_visible(false); self.is_captured = true; } if ctx.input.cursor_left { - let _ = ctx.window.set_cursor_grab(engine::CursorGrabMode::None); - ctx.window.set_cursor_visible(true); + let _ = ctx.gfx.window.set_cursor_grab(engine::CursorGrabMode::None); + ctx.gfx.window.set_cursor_visible(true); self.is_captured = false; } if ctx.input.keyboard.pressed.contains(&KeyCode::Escape) { - let _ = ctx.window.set_cursor_grab(engine::CursorGrabMode::None); - ctx.window.set_cursor_visible(true); + let _ = ctx.gfx.window.set_cursor_grab(engine::CursorGrabMode::None); + ctx.gfx.window.set_cursor_visible(true); self.is_captured = false; } diff --git a/engine_demo/src/terrain.rs b/engine_demo/src/terrain.rs index f7977a7e..cc975ea1 100644 --- a/engine_demo/src/terrain.rs +++ b/engine_demo/src/terrain.rs @@ -3,9 +3,9 @@ use engine::terrain::TerrainRender as EngineTerrainRender; use engine::{Context, FrameContext}; use geom::{vec2, Camera, InfiniteFrustrum}; -const CSIZE: usize = 256; +const CSIZE: usize = 512; const CRESO: usize = 32; -const MAP_SIZE: usize = 25; +const MAP_SIZE: usize = 75; pub struct Terrain { terrain: EngineTerrainRender, @@ -20,8 +20,6 @@ impl DemoElement for Terrain { fn init(ctx: &mut Context) -> Self { let gfx = &mut ctx.gfx; - gfx.set_define_flag("DEBUG", true); - let mut heights: Box<[[[[f32; CRESO]; CRESO]; MAP_SIZE]; MAP_SIZE]> = vec![[[[0.0; CRESO]; CRESO]; MAP_SIZE]; MAP_SIZE] .into_boxed_slice() @@ -35,7 +33,7 @@ impl DemoElement for Terrain { heights[y][x][i][j] = 600.0 * (0.5 + geom::fnoise( - 0.01 * vec2((x * CRESO + j) as f32, (y * CRESO + i) as f32), + 0.005 * vec2((x * CRESO + j) as f32, (y * CRESO + i) as f32), ) .0); } diff --git a/native_app/src/gui/windows/settings.rs b/native_app/src/gui/windows/settings.rs index 04f12f46..c34619a5 100644 --- a/native_app/src/gui/windows/settings.rs +++ b/native_app/src/gui/windows/settings.rs @@ -4,59 +4,13 @@ use crate::uiworld::UiWorld; use common::saveload::Encoder; use egui::{Align2, Context, Widget}; use egui_extras::Column; -use engine::Fullscreen; -use engine::GfxContext; +use engine::GfxSettings; +use engine::ShadowQuality; use simulation::Simulation; use std::time::{Duration, Instant}; const SETTINGS_SAVE_NAME: &str = "settings"; -#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq)] -pub enum ShadowQuality { - NoShadows, - Low, - Medium, - High, - TooHigh, -} - -impl AsRef for ShadowQuality { - fn as_ref(&self) -> &str { - match self { - ShadowQuality::NoShadows => "No Shadows", - ShadowQuality::Low => "Low", - ShadowQuality::Medium => "Medium", - ShadowQuality::High => "High", - ShadowQuality::TooHigh => "Too High", - } - } -} - -impl From for ShadowQuality { - fn from(v: u8) -> Self { - match v { - 0 => ShadowQuality::NoShadows, - 1 => ShadowQuality::Low, - 2 => ShadowQuality::Medium, - 3 => ShadowQuality::High, - 4 => ShadowQuality::TooHigh, - _ => ShadowQuality::High, - } - } -} - -impl ShadowQuality { - pub fn size(&self) -> Option { - match self { - ShadowQuality::Low => Some(512), - ShadowQuality::Medium => Some(1024), - ShadowQuality::High => Some(2048), - ShadowQuality::TooHigh => Some(4096), - ShadowQuality::NoShadows => None, - } - } -} - #[derive(Copy, Clone, Serialize, Deserialize, PartialEq)] #[serde(default)] pub struct Settings { @@ -65,12 +19,7 @@ pub struct Settings { pub camera_smooth_tightness: f32, pub camera_fov: f32, - pub fullscreen: bool, - pub vsync: bool, - pub ssao: bool, - pub shadows: ShadowQuality, - pub terrain_grid: bool, - pub fog: bool, + pub gfx: GfxSettings, pub gui_scale: f32, @@ -93,17 +42,12 @@ impl Default for Settings { music_volume_percent: 100.0, effects_volume_percent: 100.0, ui_volume_percent: 100.0, - fullscreen: false, - vsync: true, time_warp: 1, auto_save_every: AutoSaveEvery::FiveMinutes, - ssao: true, - shadows: ShadowQuality::High, camera_smooth_tightness: 1.0, camera_fov: 60.0, - terrain_grid: true, - fog: true, gui_scale: 1.0, + gfx: GfxSettings::default(), } } } @@ -219,19 +163,19 @@ pub fn settings(window: egui::Window<'_>, ui: &Context, uiworld: &mut UiWorld, _ 1000.0 * ms_to_show )); - ui.checkbox(&mut settings.fullscreen, "Fullscreen"); - ui.checkbox(&mut settings.terrain_grid, "Terrain Grid"); - ui.checkbox(&mut settings.fog, "Fog"); - ui.checkbox(&mut settings.ssao, "Ambient Occlusion (SSAO)"); + ui.checkbox(&mut settings.gfx.fullscreen, "Fullscreen"); + ui.checkbox(&mut settings.gfx.terrain_grid, "Terrain Grid"); + ui.checkbox(&mut settings.gfx.fog, "Fog"); + ui.checkbox(&mut settings.gfx.ssao, "Ambient Occlusion (SSAO)"); // shadow quality combobox - let mut id = settings.shadows as u8 as usize; + let mut id = settings.gfx.shadows as u8 as usize; egui::ComboBox::from_label("Shadow Quality").show_index(ui, &mut id, 5, |i| { ShadowQuality::from(i as u8).as_ref().to_string() }); - settings.shadows = ShadowQuality::from(id as u8); + settings.gfx.shadows = ShadowQuality::from(id as u8); - ui.checkbox(&mut settings.vsync, "VSync"); + ui.checkbox(&mut settings.gfx.vsync, "VSync"); ui.separator(); ui.label("GUI"); @@ -360,29 +304,7 @@ pub fn settings(window: egui::Window<'_>, ui: &Context, uiworld: &mut UiWorld, _ } pub fn manage_settings(ctx: &mut engine::Context, settings: &Settings) { - if settings.fullscreen && ctx.window.fullscreen().is_none() { - ctx.window - .set_fullscreen(Some(Fullscreen::Borderless(ctx.window.current_monitor()))) - } - if !settings.fullscreen && ctx.window.fullscreen().is_some() { - ctx.window.set_fullscreen(None); - } - - ctx.gfx.set_vsync(settings.vsync); - let params = ctx.gfx.render_params.value_mut(); - params.shadow_mapping_resolution = settings.shadows.size().unwrap_or(0) as i32; - - if let Some(v) = settings.shadows.size() { - if ctx.gfx.sun_shadowmap.extent.width != v { - ctx.gfx.sun_shadowmap = GfxContext::mk_shadowmap(&ctx.gfx.device, v); - ctx.gfx.update_simplelit_bg(); - } - } - - ctx.gfx.set_define_flag("FOG", settings.fog); - ctx.gfx.set_define_flag("SSAO", settings.ssao); - ctx.gfx - .set_define_flag("TERRAIN_GRID", settings.terrain_grid); + ctx.gfx.update_settings(settings.gfx); ctx.egui.zoom_factor = settings.gui_scale;