diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:22 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:22 +0100 |
commit | b688a25810840c5ebf4bf2c18bbdae52c62f6b4d (patch) | |
tree | 923c81d1be62d1344694306d5fb8728841620b6f /stockton-render | |
parent | bf9573764c695e65b1504419fafb76ccabb0322b (diff) |
feat(render): WIP eGUI integration
Diffstat (limited to 'stockton-render')
-rw-r--r-- | stockton-render/Cargo.toml | 5 | ||||
-rw-r--r-- | stockton-render/src/draw/context.rs | 63 | ||||
-rw-r--r-- | stockton-render/src/draw/draw_buffers.rs | 8 | ||||
-rw-r--r-- | stockton-render/src/draw/macros.rs | 28 | ||||
-rw-r--r-- | stockton-render/src/draw/render.rs | 2 | ||||
-rw-r--r-- | stockton-render/src/draw/target.rs | 8 | ||||
-rw-r--r-- | stockton-render/src/draw/ui/data/stockton.frag | 11 | ||||
-rw-r--r-- | stockton-render/src/draw/ui/data/stockton.vert | 27 | ||||
-rw-r--r-- | stockton-render/src/draw/ui/mod.rs | 8 | ||||
-rw-r--r-- | stockton-render/src/draw/ui/pipeline.rs | 18 | ||||
-rw-r--r-- | stockton-render/src/draw/ui/render.rs | 55 | ||||
-rwxr-xr-x | stockton-render/src/draw/ui/texture.rs | 54 | ||||
-rw-r--r-- | stockton-render/src/lib.rs | 14 | ||||
-rw-r--r-- | stockton-render/src/window.rs | 124 |
14 files changed, 365 insertions, 60 deletions
diff --git a/stockton-render/Cargo.toml b/stockton-render/Cargo.toml index e4f2153..7c69be6 100644 --- a/stockton-render/Cargo.toml +++ b/stockton-render/Cargo.toml @@ -12,10 +12,11 @@ winit = "^0.21" gfx-hal = "^0.5" arrayvec = "0.4.10" nalgebra-glm = "^0.6" -shaderc = "0.6.1" +shaderc = "^0.7" log = "0.4.0" -image = "0.23.2" +image = "0.23.11" legion = { version = "^0.3" } +egui = "^0.2" [features] default = ["vulkan"] diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index 94f1f0c..4d700e5 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -29,14 +29,14 @@ use winit::window::Window; use super::{ buffer::ModifiableBuffer, - draw_buffers::DrawBuffers, + draw_buffers::{DrawBuffers, UVPoint}, pipeline::CompletePipeline, render::do_render, target::{SwapchainProperties, TargetChain}, texture::TextureStore, - ui::{do_render as do_render_ui, UIPipeline}, + ui::{do_render as do_render_ui, ensure_textures as ensure_textures_ui, UIPipeline, UIPoint}, }; -use crate::{error, types::*}; +use crate::{error, types::*, window::UIState}; use stockton_levels::prelude::*; /// Contains all the hal related stuff. @@ -76,14 +76,19 @@ pub struct RenderingContext<'a> { /// Texture store texture_store: ManuallyDrop<TextureStore>, + /// Texture store for UI + ui_texture_store: ManuallyDrop<TextureStore>, + /// Buffers used for drawing - draw_buffers: ManuallyDrop<DrawBuffers<'a>>, + draw_buffers: ManuallyDrop<DrawBuffers<'a, UVPoint>>, /// Buffers used for drawing the UI - ui_draw_buffers: ManuallyDrop<DrawBuffers<'a>>, + ui_draw_buffers: ManuallyDrop<DrawBuffers<'a, UIPoint>>, /// View projection matrix pub(crate) vp_matrix: Mat4, + + pub(crate) pixels_per_point: f32, } impl<'a> RenderingContext<'a> { @@ -156,9 +161,21 @@ impl<'a> RenderingContext<'a> { file, )?; + // Texture store for UI elements + let ui_texture_store = TextureStore::new_empty( + &mut device, + &mut adapter, + &mut queue_group.queues[0], + &mut cmd_pool, + 1, // TODO + )?; + let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new(); descriptor_set_layouts.push(texture_store.descriptor_set_layout.deref()); + let mut ui_descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new(); + ui_descriptor_set_layouts.push(ui_texture_store.descriptor_set_layout.deref()); + // Graphics pipeline let pipeline = CompletePipeline::new( &mut device, @@ -172,7 +189,7 @@ impl<'a> RenderingContext<'a> { &mut device, swapchain_properties.extent, &swapchain_properties, - &[], + ui_descriptor_set_layouts, )?; // Swapchain and associated resources @@ -207,7 +224,11 @@ impl<'a> RenderingContext<'a> { draw_buffers: ManuallyDrop::new(draw_buffers), ui_draw_buffers: ManuallyDrop::new(ui_draw_buffers), + ui_texture_store: ManuallyDrop::new(ui_texture_store), + vp_matrix: Mat4::identity(), + + pixels_per_point: window.scale_factor() as f32, }) } @@ -241,7 +262,15 @@ impl<'a> RenderingContext<'a> { // TODO: Recycle ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut self.device); self.ui_pipeline = ManuallyDrop::new({ - UIPipeline::new(&mut self.device, properties.extent, &properties, &[])? + let mut descriptor_set_layouts: ArrayVec<[_; 1]> = ArrayVec::new(); + descriptor_set_layouts.push(self.ui_texture_store.descriptor_set_layout.deref()); + + UIPipeline::new( + &mut self.device, + properties.extent, + &properties, + descriptor_set_layouts, + )? }); let old_swapchain = ManuallyDrop::into_inner(read(&self.target_chain)) @@ -267,8 +296,19 @@ impl<'a> RenderingContext<'a> { pub fn draw_vertices<M: MinBSPFeatures<VulkanSystem>>( &mut self, file: &M, + ui: &mut UIState, faces: &[u32], ) -> Result<(), &'static str> { + // Ensure UI texture(s) are loaded + ensure_textures_ui( + &mut self.ui_texture_store, + ui, + &mut self.device, + &mut self.adapter, + &mut self.queue_group.queues[0], + &mut self.cmd_pool, + ); + // 3D Pass let cmd_buffer = self.target_chain.prep_next_target( &mut self.device, @@ -289,7 +329,13 @@ impl<'a> RenderingContext<'a> { let cmd_buffer = self .target_chain .target_2d_pass(&mut self.ui_draw_buffers, &self.ui_pipeline)?; - do_render_ui(cmd_buffer, &mut self.ui_draw_buffers); + do_render_ui( + cmd_buffer, + &self.ui_pipeline.pipeline_layout, + &mut self.ui_draw_buffers, + &mut self.ui_texture_store, + ui, + ); // Update our buffers before we actually start drawing self.draw_buffers.vertex_buffer.commit( @@ -334,6 +380,7 @@ impl<'a> core::ops::Drop for RenderingContext<'a> { ManuallyDrop::into_inner(read(&self.draw_buffers)).deactivate(&mut self.device); ManuallyDrop::into_inner(read(&self.ui_draw_buffers)).deactivate(&mut self.device); ManuallyDrop::into_inner(read(&self.texture_store)).deactivate(&mut self.device); + ManuallyDrop::into_inner(read(&self.ui_texture_store)).deactivate(&mut self.device); ManuallyDrop::into_inner(read(&self.target_chain)) .deactivate(&mut self.device, &mut self.cmd_pool); diff --git a/stockton-render/src/draw/draw_buffers.rs b/stockton-render/src/draw/draw_buffers.rs index a6e0996..837356a 100644 --- a/stockton-render/src/draw/draw_buffers.rs +++ b/stockton-render/src/draw/draw_buffers.rs @@ -31,13 +31,13 @@ pub const INITIAL_VERT_SIZE: u64 = 3 * 3000; pub const INITIAL_INDEX_SIZE: u64 = 3000; /// The buffers used for drawing, ie index and vertex buffer -pub struct DrawBuffers<'a> { - pub vertex_buffer: ManuallyDrop<StagedBuffer<'a, UVPoint>>, +pub struct DrawBuffers<'a, T: Sized> { + pub vertex_buffer: ManuallyDrop<StagedBuffer<'a, T>>, pub index_buffer: ManuallyDrop<StagedBuffer<'a, (u16, u16, u16)>>, } -impl<'a> DrawBuffers<'a> { - pub fn new(device: &mut Device, adapter: &Adapter) -> Result<DrawBuffers<'a>, CreationError> { +impl<'a, T> DrawBuffers<'a, T> { + pub fn new(device: &mut Device, adapter: &Adapter) -> Result<DrawBuffers<'a, T>, CreationError> { let vert = StagedBuffer::new(device, &adapter, Usage::VERTEX, INITIAL_VERT_SIZE)?; let index = StagedBuffer::new(device, &adapter, Usage::INDEX, INITIAL_INDEX_SIZE)?; diff --git a/stockton-render/src/draw/macros.rs b/stockton-render/src/draw/macros.rs index 9096958..e1ee515 100644 --- a/stockton-render/src/draw/macros.rs +++ b/stockton-render/src/draw/macros.rs @@ -29,6 +29,20 @@ /// ``` /// See the hal::pso::Format enum for possible types macro_rules! pipeline_vb_attributes { + // Special case for single item + ( $binding:expr, $firstSize:expr; $firstType:ident ) => ({ + vec![ + AttributeDesc { + location: 0, + binding: $binding, + element: Element { + format: Format::$firstType, + offset: $firstSize as u32 + } + } + ] + }); + // Start of recursion ( $binding:expr, $firstSize:expr; $firstType:ident, @@ -55,20 +69,6 @@ macro_rules! pipeline_vb_attributes { vec }); - // Special case for single item - ( $binding:expr; $firstSize:expr; $firstType:ident ) => ({ - vec![ - AttributeDesc { - location: 0, - binding: $binding, - element: Element { - format: Format::$firstType, - offset: $firstSize as u32 - } - } - ] - }); - // Middle of recursion ( $vec:ident; $binding:expr; $location:expr; $prevSize:expr, $firstSize:expr; $firstType:ident, diff --git a/stockton-render/src/draw/render.rs b/stockton-render/src/draw/render.rs index e73b569..093e257 100644 --- a/stockton-render/src/draw/render.rs +++ b/stockton-render/src/draw/render.rs @@ -31,7 +31,7 @@ use crate::types::*; pub fn do_render<M: MinBSPFeatures<VulkanSystem>>( cmd_buffer: &mut CommandBuffer, - draw_buffers: &mut DrawBuffers, + draw_buffers: &mut DrawBuffers<UVPoint>, texture_store: &TextureStore, pipeline_layout: &PipelineLayout, file: &M, diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs index b47700f..daf9942 100644 --- a/stockton-render/src/draw/target.rs +++ b/stockton-render/src/draw/target.rs @@ -31,8 +31,8 @@ use hal::{ use na::Mat4; use super::{ - buffer::ModifiableBuffer, draw_buffers::DrawBuffers, pipeline::CompletePipeline, - texture::image::LoadedImage, ui::UIPipeline, + buffer::ModifiableBuffer, draw_buffers::{DrawBuffers, UVPoint}, pipeline::CompletePipeline, + texture::image::LoadedImage, ui::{UIPipeline, UIPoint}, }; use crate::types::*; @@ -275,7 +275,7 @@ impl TargetChain { pub fn prep_next_target<'a>( &'a mut self, device: &mut Device, - draw_buffers: &mut DrawBuffers, + draw_buffers: &mut DrawBuffers<UVPoint>, pipeline: &CompletePipeline, vp: &Mat4, ) -> Result<&'a mut crate::types::CommandBuffer, &'static str> { @@ -373,7 +373,7 @@ impl TargetChain { pub fn target_2d_pass<'a>( &'a mut self, - draw_buffers: &mut DrawBuffers, + draw_buffers: &mut DrawBuffers<UIPoint>, pipeline: &UIPipeline, ) -> Result<&'a mut CommandBuffer, &'static str> { let target = &mut self.targets[self.last_image as usize]; diff --git a/stockton-render/src/draw/ui/data/stockton.frag b/stockton-render/src/draw/ui/data/stockton.frag index 1a85ab6..e5b2b4d 100644 --- a/stockton-render/src/draw/ui/data/stockton.frag +++ b/stockton-render/src/draw/ui/data/stockton.frag @@ -1,8 +1,15 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable -layout(location = 0) out vec4 outColor; +// DescriptorSet 0 = Textures +layout(set = 0, binding = 0) uniform texture2D tex[8]; +layout(set = 0, binding = 1) uniform sampler samp[8]; + +layout (location = 1) in vec2 frag_uv; +layout (location = 2) in flat int frag_col; + +layout (location = 0) out vec4 color; void main() { - outColor = vec4(1.0, 0.0, 0.0, 1.0); + color = texture(sampler2D(tex[0], samp[0]), frag_uv); }
\ No newline at end of file diff --git a/stockton-render/src/draw/ui/data/stockton.vert b/stockton-render/src/draw/ui/data/stockton.vert index 1dd9477..7447fec 100644 --- a/stockton-render/src/draw/ui/data/stockton.vert +++ b/stockton-render/src/draw/ui/data/stockton.vert @@ -1,11 +1,26 @@ #version 450 -vec2 positions[3] = vec2[]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); +layout (push_constant) uniform PushConsts { + vec2 screen_size; +} push; + +layout(location = 0) in vec2 pos; +layout (location = 1) in vec2 uv; +layout (location = 2) in int col; // rgba of u8s + +out gl_PerVertex { + vec4 gl_Position; +}; +layout (location = 1) out vec2 frag_uv; +layout (location = 2) out int frag_col; void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + gl_Position = vec4( + ((pos.x / push.screen_size.x) * 2.0) - 1.0, + ((pos.y / push.screen_size.y) * 2.0) - 1.0, + 0.0, + 1.0 + ); + frag_uv = uv; + frag_col = col; } diff --git a/stockton-render/src/draw/ui/mod.rs b/stockton-render/src/draw/ui/mod.rs index cd19362..bcf5f38 100644 --- a/stockton-render/src/draw/ui/mod.rs +++ b/stockton-render/src/draw/ui/mod.rs @@ -15,8 +15,16 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +use egui::paint::color::Srgba; + pub mod pipeline; pub mod render; +pub mod texture; pub use pipeline::UIPipeline; pub use render::do_render; +use stockton_types::Vector2; +pub use texture::ensure_textures; + +#[derive(Debug)] +pub struct UIPoint(pub Vector2, pub Vector2, pub Srgba); diff --git a/stockton-render/src/draw/ui/pipeline.rs b/stockton-render/src/draw/ui/pipeline.rs index 378c558..3b643e4 100644 --- a/stockton-render/src/draw/ui/pipeline.rs +++ b/stockton-render/src/draw/ui/pipeline.rs @@ -62,7 +62,7 @@ impl UIPipeline { set_layouts: T, ) -> Result<Self, error::CreationError> where - T: IntoIterator, + T: IntoIterator + std::fmt::Debug, T::Item: Borrow<DescriptorSetLayout>, { use hal::format::Format; @@ -125,7 +125,7 @@ impl UIPipeline { .compile_into_spirv( VERTEX_SOURCE, shaderc::ShaderKind::Vertex, - "vertex.vert", + "vertex_ui.vert", ENTRY_NAME, None, ) @@ -135,7 +135,7 @@ impl UIPipeline { .compile_into_spirv( FRAGMENT_SOURCE, shaderc::ShaderKind::Fragment, - "fragment.frag", + "fragment_ui.frag", ENTRY_NAME, None, ) @@ -180,13 +180,14 @@ impl UIPipeline { // Vertex buffers let vertex_buffers: Vec<VertexBufferDesc> = vec![VertexBufferDesc { binding: 0, - stride: (size_of::<f32>() * 5) as u32, + stride: ((size_of::<f32>() * 4) + (size_of::<u8>() * 4)) as u32, rate: VertexInputRate::Vertex, }]; let attributes: Vec<AttributeDesc> = pipeline_vb_attributes!(0, size_of::<f32>() * 2; Rg32Sfloat, - size_of::<f32>() * 3; Rgb32Sfloat + size_of::<f32>() * 2; Rg32Sfloat, + size_of::<u8>() * 4; Rgba8Uint ); // Rasterizer @@ -207,9 +208,12 @@ impl UIPipeline { stencil: None, }; + log::debug!("ui set layouts: {:?}", set_layouts); // Pipeline layout - let layout = unsafe { device.create_pipeline_layout(set_layouts, &[]) } - .map_err(|_| error::CreationError::OutOfMemoryError)?; + let layout = unsafe { + device.create_pipeline_layout(set_layouts, &[(ShaderStageFlags::VERTEX, 0..8)]) + } + .map_err(|_| error::CreationError::OutOfMemoryError)?; // Colour blending let blender = { diff --git a/stockton-render/src/draw/ui/render.rs b/stockton-render/src/draw/ui/render.rs index b965a80..ad23dfb 100644 --- a/stockton-render/src/draw/ui/render.rs +++ b/stockton-render/src/draw/ui/render.rs @@ -15,14 +15,65 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +use crate::draw::texture::TextureStore; +use arrayvec::ArrayVec; +use egui::Pos2; use hal::prelude::*; +use hal::pso::ShaderStageFlags; +use super::UIPoint; use crate::draw::draw_buffers::DrawBuffers; use crate::types::*; +use crate::UIState; +use std::convert::TryInto; +use std::mem::transmute; +use stockton_types::Vector2; -pub fn do_render(cmd_buffer: &mut CommandBuffer, _draw_buffers: &mut DrawBuffers) { +pub fn do_render( + cmd_buffer: &mut CommandBuffer, + pipeline_layout: &PipelineLayout, + draw_buffers: &mut DrawBuffers<UIPoint>, + texture_store: &mut TextureStore, + ui: &mut UIState, +) { // TODO: Actual UI Rendering + let (_out, paint) = ui.end_frame(); + let screen = ui.dimensions(); + unsafe { - cmd_buffer.draw(0..3, 0..1); + cmd_buffer.push_graphics_constants( + &pipeline_layout, + ShaderStageFlags::VERTEX, + 0, + &[transmute(screen.x), transmute(screen.y)], + ); + } + + for (_rect, tris) in paint.iter() { + // Copy triangles/indicies + for i in (0..tris.indices.len()).step_by(3) { + draw_buffers.index_buffer[i / 3] = ( + tris.indices[i].try_into().unwrap(), + tris.indices[i + 1].try_into().unwrap(), + tris.indices[i + 2].try_into().unwrap(), + ); + } + for (i, vertex) in tris.vertices.iter().enumerate() { + draw_buffers.vertex_buffer[i] = UIPoint( + Vector2::new(vertex.pos.x, vertex.pos.y), + Vector2::new(vertex.uv.x, vertex.uv.y), + vertex.color, + ); + } + + // TODO: *Properly* deal with textures + let mut descriptor_sets: ArrayVec<[_; 1]> = ArrayVec::new(); + descriptor_sets.push(texture_store.get_chunk_descriptor_set(0)); + + unsafe { + cmd_buffer.bind_graphics_descriptor_sets(pipeline_layout, 0, descriptor_sets, &[]); + // Call draw + cmd_buffer.draw_indexed(0..tris.indices.len() as u32, 0, 0..1); + } } } diff --git a/stockton-render/src/draw/ui/texture.rs b/stockton-render/src/draw/ui/texture.rs new file mode 100755 index 0000000..ce18f02 --- /dev/null +++ b/stockton-render/src/draw/ui/texture.rs @@ -0,0 +1,54 @@ +/* + * Copyright (C) Oscar Shrimpton 2020 + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ +use egui::Texture; +use crate::types::*; +use crate::draw::texture::{TextureStore, LoadableImage}; +use crate::UIState; + +impl LoadableImage for &Texture { + fn width(&self) -> u32 { + self.width as u32 + } + fn height(&self) -> u32 { + self.height as u32 + } + fn copy_row(&self, y: u32, ptr: *mut u8) -> () { + let row_size = self.width(); + let pixels = &self.pixels[(y * row_size) as usize..((y + 1) * row_size) as usize]; + + for (i,x) in pixels.iter().enumerate() { + unsafe { + *ptr.offset(i as isize * 3) = *x; + *ptr.offset((i as isize * 3) + 1) = *x; + *ptr.offset((i as isize * 3) + 2) = *x; + } + } + } +} + +pub fn ensure_textures(texture_store: &mut TextureStore, ui: &mut UIState, + device: &mut Device, + adapter: &mut Adapter, + command_queue: &mut CommandQueue, + command_pool: &mut CommandPool) { + let tex = ui.ctx.texture(); + + if tex.version != ui.last_tex_ver { + texture_store.put_texture(0, &*tex, device, adapter, command_queue, command_pool).unwrap(); // TODO + ui.last_tex_ver = tex.version; + } +}
\ No newline at end of file diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs index 8bdca89..221bdd5 100644 --- a/stockton-render/src/lib.rs +++ b/stockton-render/src/lib.rs @@ -28,6 +28,7 @@ pub mod draw; mod error; mod types; pub mod window; +pub mod systems; use culling::get_visible_faces; use draw::RenderingContext; @@ -36,7 +37,7 @@ use legion::IntoQuery; use std::sync::mpsc::{Receiver, Sender}; use std::sync::Arc; use std::sync::RwLock; -pub use window::WindowEvent; +pub use window::{WindowEvent, UIState}; use stockton_levels::prelude::*; use stockton_types::components::{CameraSettings, Transform}; @@ -50,7 +51,7 @@ use std::sync::mpsc::channel; /// Also takes ownership of the window and channels window events to be processed outside winit's event loop. pub struct Renderer<'a> { /// All the vulkan stuff - context: RenderingContext<'a>, + pub(crate) context: RenderingContext<'a>, /// For getting events from the winit event loop pub window_events: Receiver<WindowEvent>, @@ -79,16 +80,16 @@ impl<'a> Renderer<'a> { } /// Render a single frame of the given map. - fn render<T: MinBSPFeatures<VulkanSystem>>(&mut self, map: &T, pos: Vector3) { + fn render<T: MinBSPFeatures<VulkanSystem>>(&mut self, map: &T, ui: &mut UIState, pos: Vector3) { // Get visible faces let faces = get_visible_faces(pos, map); // Then draw them - if self.context.draw_vertices(map, &faces).is_err() { + if self.context.draw_vertices(map, ui, &faces).is_err() { unsafe { self.context.handle_surface_change().unwrap() }; // If it fails twice, then error - self.context.draw_vertices(map, &faces).unwrap(); + self.context.draw_vertices(map, ui, &faces).unwrap(); } } @@ -103,11 +104,12 @@ impl<'a> Renderer<'a> { #[read_component(CameraSettings)] pub fn do_render<T: 'static + MinBSPFeatures<VulkanSystem>>( #[resource] renderer: &mut Renderer<'static>, + #[resource] ui: &mut UIState, #[resource] map: &T, world: &SubWorld, ) { let mut query = <(&Transform, &CameraSettings)>::query(); for (transform, _) in query.iter(world) { - renderer.render(map, transform.position); + renderer.render(map, ui, transform.position); } } diff --git a/stockton-render/src/window.rs b/stockton-render/src/window.rs index efb8030..e122dea 100644 --- a/stockton-render/src/window.rs +++ b/stockton-render/src/window.rs @@ -15,20 +15,27 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +use log::debug; +use std::sync::Arc; +use egui::Context; use crate::Renderer; use legion::systems::Runnable; +use egui::{RawInput, Ui, Pos2, Output, PaintJobs}; + use stockton_input::{Action as KBAction, InputManager, Mouse}; -use winit::event::{ElementState, Event as WinitEvent, WindowEvent as WinitWindowEvent}; +use winit::event::{ElementState, Event as WinitEvent, WindowEvent as WinitWindowEvent, MouseButton}; use winit::event_loop::ControlFlow; #[derive(Debug, Clone, Copy)] pub enum WindowEvent { - SizeChanged, + SizeChanged (u32, u32), CloseRequested, KeyboardAction(KBAction), + MouseAction(KBAction), MouseMoved(f32, f32), + MouseLeft } impl WindowEvent { @@ -37,7 +44,7 @@ impl WindowEvent { match winit_event { WinitEvent::WindowEvent { event, .. } => match event { WinitWindowEvent::CloseRequested => Some(WindowEvent::CloseRequested), - WinitWindowEvent::Resized(_) => Some(WindowEvent::SizeChanged), + WinitWindowEvent::Resized(size) => Some(WindowEvent::SizeChanged (size.width, size.height)), WinitWindowEvent::KeyboardInput { input, .. } => match input.state { ElementState::Pressed => Some(WindowEvent::KeyboardAction(KBAction::KeyPress( input.scancode, @@ -50,6 +57,20 @@ impl WindowEvent { position.x as f32, position.y as f32, )), + WinitWindowEvent::CursorLeft { .. } => Some(WindowEvent::MouseLeft), + WinitWindowEvent::MouseInput { button, state, .. } => { + let mb: stockton_input::MouseButton = match button { + MouseButton::Left => stockton_input::MouseButton::Left, + MouseButton::Right => stockton_input::MouseButton::Right, + MouseButton::Middle => stockton_input::MouseButton::Middle, + MouseButton::Other(x) => stockton_input::MouseButton::Other(*x) + }; + + match state { + ElementState::Pressed => Some(WindowEvent::MouseAction(KBAction::MousePress(mb))), + ElementState::Released => Some(WindowEvent::MouseAction(KBAction::MouseRelease(mb))) + } + }, _ => None, }, _ => None, @@ -57,12 +78,87 @@ impl WindowEvent { } } +pub struct UIState { + pub(crate) ctx: Arc<Context>, + pub(crate) raw_input: RawInput, + ui: Option<Ui>, + + pub(crate) last_tex_ver: u64, +} + +impl UIState { + pub fn ui<'a>(&'a mut self) -> &'a mut Ui { + if self.ui.is_none() { + self.ui = Some(self.begin_frame()); + } + self.ui.as_mut().unwrap() + } + fn begin_frame(&mut self) -> Ui { + self.ctx.begin_frame(self.raw_input.take()) + } + + pub fn end_frame(&mut self) -> (Output, PaintJobs) { + self.ui = None; + self.ctx.end_frame() + } + + fn set_mouse_pos(&mut self, x: f32, y: f32) { + self.raw_input.mouse_pos = Some(Pos2 {x, y}) + } + + fn set_mouse_left(&mut self) { + self.raw_input.mouse_pos = None; + } + fn set_dimensions(&mut self, w: u32, h: u32) { + self.raw_input.screen_size = egui::math::Vec2 { + x: w as f32, + y: h as f32 + } + } + fn set_pixels_per_point(&mut self, ppp: Option<f32>) { + self.raw_input.pixels_per_point = ppp; + } + + pub fn dimensions(&self) -> egui::math::Vec2 { + self.raw_input.screen_size + } + + fn handle_action(&mut self, action: KBAction) { + // TODO + match action { + KBAction::MousePress(stockton_input::MouseButton::Left) => { + self.raw_input.mouse_down = true; + } + KBAction::MouseRelease(stockton_input::MouseButton::Right) => { + self.raw_input.mouse_down = false; + } + _ => () + } + } + + pub fn new(renderer: &Renderer) -> Self { + let mut state = UIState { + ctx: Context::new(), + raw_input: RawInput::default(), + ui: None, + last_tex_ver: 0 + }; + + let props = &renderer.context.target_chain.properties; + state.set_dimensions(props.extent.width, props.extent.height); + state.set_pixels_per_point(Some(renderer.context.pixels_per_point)); + debug!("{:?}", state.raw_input); + state + } +} + #[system] /// A system to process the window events sent to renderer by the winit event loop. pub fn _process_window_events<T: 'static + InputManager>( #[resource] renderer: &mut Renderer<'static>, #[resource] manager: &mut T, #[resource] mouse: &mut Mouse, + #[resource] ui_state: &mut UIState, #[state] actions_buf: &mut Vec<KBAction>, ) { let mut actions_buf_cursor = 0; @@ -70,7 +166,10 @@ pub fn _process_window_events<T: 'static + InputManager>( while let Ok(event) = renderer.window_events.try_recv() { match event { - WindowEvent::SizeChanged => renderer.resize(), + WindowEvent::SizeChanged(w, h) => { + renderer.resize(); + ui_state.set_dimensions(w, h); + }, WindowEvent::CloseRequested => { let mut flow = renderer.update_control_flow.write().unwrap(); // TODO: Let everything know this is our last frame @@ -83,10 +182,27 @@ pub fn _process_window_events<T: 'static + InputManager>( actions_buf[actions_buf_cursor] = action; } actions_buf_cursor += 1; + + ui_state.handle_action(action); } WindowEvent::MouseMoved(x, y) => { mouse_delta.x = x; mouse_delta.y = y; + + ui_state.set_mouse_pos(x, y); + }, + WindowEvent::MouseLeft => { + ui_state.set_mouse_left(); + }, + WindowEvent::MouseAction(action) => { + if actions_buf_cursor >= actions_buf.len() { + actions_buf.push(action); + } else { + actions_buf[actions_buf_cursor] = action; + } + actions_buf_cursor += 1; + + ui_state.handle_action(action); } }; } |