diff options
Diffstat (limited to 'stockton-render')
-rw-r--r-- | stockton-render/Cargo.toml | 22 | ||||
-rw-r--r-- | stockton-render/src/data/3d.frag | 15 | ||||
-rw-r--r-- | stockton-render/src/data/3d.vert | 23 | ||||
-rw-r--r-- | stockton-render/src/data/ui.frag | 15 | ||||
-rw-r--r-- | stockton-render/src/data/ui.vert | 37 | ||||
-rw-r--r-- | stockton-render/src/level.rs | 554 | ||||
-rw-r--r-- | stockton-render/src/lib.rs | 8 | ||||
-rw-r--r-- | stockton-render/src/ui.rs | 421 | ||||
-rw-r--r-- | stockton-render/src/window.rs | 278 |
9 files changed, 0 insertions, 1373 deletions
diff --git a/stockton-render/Cargo.toml b/stockton-render/Cargo.toml deleted file mode 100644 index 3ba8c01..0000000 --- a/stockton-render/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "stockton-render" -version = "0.1.0" -authors = ["tcmal <oscar.shrimpton.personal@gmail.com>"] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -stockton-skeleton = { path = "../stockton-skeleton" } -stockton-levels = { path = "../stockton-levels" } -stockton-input = { path = "../stockton-input" } -anyhow = "1.0.40" -egui = "^0.12" -epaint = "^0.12" -gfx-hal = "^0.8.0" -shaderc = "^0.7" -legion = { version = "^0.3" } -log = "0.4.0" -winit = "^0.21" -nalgebra-glm = "^0.6" -thiserror = "1.0.25" diff --git a/stockton-render/src/data/3d.frag b/stockton-render/src/data/3d.frag deleted file mode 100644 index 336d9fe..0000000 --- a/stockton-render/src/data/3d.frag +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 - -// 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_tex; - -layout (location = 0) out vec4 color; - -void main() -{ - color = texture(sampler2D(tex[frag_tex % 8], samp[frag_tex % 8]), frag_uv); -}
\ No newline at end of file diff --git a/stockton-render/src/data/3d.vert b/stockton-render/src/data/3d.vert deleted file mode 100644 index aaee1a5..0000000 --- a/stockton-render/src/data/3d.vert +++ /dev/null @@ -1,23 +0,0 @@ -#version 450 - -// DescriptorSet 0 = Matrices -layout (push_constant) uniform PushConsts { - mat4 vp; -} push; - -layout (location = 0) in vec3 position; -layout (location = 1) in int tex; -layout (location = 2) in vec2 uv; - -out gl_PerVertex { - vec4 gl_Position; -}; -layout (location = 1) out vec2 frag_uv; -layout (location = 2) out flat int frag_tex; - -void main() -{ - gl_Position = push.vp * vec4(position, 1.0); - frag_uv = uv; - frag_tex = tex; -}
\ No newline at end of file diff --git a/stockton-render/src/data/ui.frag b/stockton-render/src/data/ui.frag deleted file mode 100644 index c30c99e..0000000 --- a/stockton-render/src/data/ui.frag +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -// 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 vec4 frag_col; - -layout (location = 0) out vec4 color; - -void main() { - color = texture(sampler2D(tex[0], samp[0]), frag_uv) * frag_col; -}
\ No newline at end of file diff --git a/stockton-render/src/data/ui.vert b/stockton-render/src/data/ui.vert deleted file mode 100644 index 8912e96..0000000 --- a/stockton-render/src/data/ui.vert +++ /dev/null @@ -1,37 +0,0 @@ -#version 450 - -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 vec4 col; - -out gl_PerVertex { - vec4 gl_Position; -}; -layout (location = 1) out vec2 frag_uv; -layout (location = 2) out vec4 frag_col; - -vec3 linear_from_srgb(vec3 srgb) { - bvec3 cutoff = lessThan(srgb, vec3(10.31475)); - vec3 lower = srgb / vec3(3294.6); - vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4)); - return mix(higher, lower, cutoff); -} - -vec4 linear_from_srgba(vec4 srgba) { - return vec4(linear_from_srgb(srgba.rgb * 255.0), srgba.a); -} - -void main() { - gl_Position = vec4( - 2.0 * pos.x / push.screen_size.x - 1.0, - 2.0 * pos.y / push.screen_size.y - 1.0, - 0.0, - 1.0 - ); - frag_uv = uv; - frag_col = linear_from_srgba(col); -} diff --git a/stockton-render/src/level.rs b/stockton-render/src/level.rs deleted file mode 100644 index dd4d61a..0000000 --- a/stockton-render/src/level.rs +++ /dev/null @@ -1,554 +0,0 @@ -//! Minimal code for drawing any level, based on traits from stockton-levels - -use stockton_levels::{ - features::MinRenderFeatures, - parts::{data::Geometry, IsFace}, -}; -use stockton_skeleton::{ - buffers::{ - draw::{DrawBuffers, INITIAL_INDEX_SIZE, INITIAL_VERT_SIZE}, - image::{BoundImageView, ImageSpec, DEPTH_RESOURCES}, - }, - builders::{ - AttachmentSpec, CompletePipeline, PipelineSpecBuilder, RenderpassSpec, ShaderDesc, - VertexBufferSpec, VertexPrimitiveAssemblerSpec, - }, - RenderingContext, - Session, - DrawPass, IntoDrawPass, PassPosition, - draw_passes::{util::TargetSpecificResources}, - error::LockPoisoned, - mem::{DataPool, DepthBufferPool, StagingPool, TexturesPool}, - queue_negotiator::QueueFamilyNegotiator, - texture::{TextureResolver, TexLoadQueue, TextureLoadConfig, TextureRepo}, - types::*, - components::{CameraSettings, Transform}, -}; - -use anyhow::{Context, Result}; -use hal::{ - buffer::SubRange, - command::{ClearColor, ClearDepthStencil, ClearValue, RenderAttachmentInfo, SubpassContents}, - format::Format, - image::{Filter, FramebufferAttachment, Layout, Usage, ViewCapabilities, WrapMode}, - pass::{Attachment, AttachmentLoadOp, AttachmentOps, AttachmentStoreOp}, - pso::{ - BlendDesc, BlendOp, BlendState, ColorBlendDesc, ColorMask, Comparison, DepthStencilDesc, - DepthTest, Face, Factor, FrontFace, InputAssemblerDesc, LogicOp, PolygonMode, Primitive, - Rasterizer, ShaderStageFlags, State, VertexInputRate, - }, -}; -use legion::{Entity, IntoQuery}; -use na::{look_at_lh, perspective_lh_zo}; -use shaderc::ShaderKind; -use std::{ - array::IntoIter, - convert::TryInto, - iter::{empty, once}, - marker::PhantomData, - sync::{Arc, RwLock}, -}; -use thiserror::Error; - -/// The Vertexes that go to the shader -#[derive(Debug, Clone, Copy)] -struct UvPoint(pub Vector3, pub i32, pub Vector2); - -/// Draw a level -pub struct LevelDrawPass<'a, M> { - repo: TextureRepo<TexturesPool, StagingPool>, - active_camera: Entity, - draw_buffers: DrawBuffers<'a, UvPoint, DataPool, StagingPool>, - surface_resources: SurfaceDependentResources, - _d: PhantomData<M>, -} - -impl<'a, M, P: PassPosition> DrawPass<P> for LevelDrawPass<'a, M> -where - M: for<'b> MinRenderFeatures<'b> + 'static, -{ - fn queue_draw( - &mut self, - session: &Session, - img_view: &ImageViewT, - cmd_buffer: &mut CommandBufferT, - ) -> anyhow::Result<()> { - // We might have loaded more textures - self.repo.process_responses(); - - // Make sure we update the vertex buffers after they're written to, but before they're read from. - self.draw_buffers - .vertex_buffer - .record_commit_cmds(cmd_buffer)?; - self.draw_buffers - .index_buffer - .record_commit_cmds(cmd_buffer)?; - - // Get level & camera - let mut query = <(&Transform, &CameraSettings)>::query(); - let (camera_transform, camera_settings) = query - .get(&session.world, self.active_camera) - .context("Couldn't find camera components")?; - - let camera_vp = { - let aspect_ratio = self.surface_resources.pipeline.render_area.w as f32 - / self.surface_resources.pipeline.render_area.h as f32; - - // Get look direction from euler angles - let direction = euler_to_direction(&camera_transform.rotation); - - // Converts world space to camera space - let view_matrix = look_at_lh( - &camera_transform.position, - &(camera_transform.position + direction), - &Vector3::new(0.0, 1.0, 0.0), - ); - - // Converts camera space to screen space - let projection_matrix = { - let mut temp = perspective_lh_zo( - aspect_ratio, - camera_settings.fov, - camera_settings.near, - camera_settings.far, - ); - - // Vulkan's co-ord system is different from OpenGLs - temp[(1, 1)] *= -1.0; - - temp - }; - - // Chain them together into a single matrix - projection_matrix * view_matrix - }; - let map_lock: Arc<RwLock<M>> = session.resources.get::<Arc<RwLock<M>>>().unwrap().clone(); - let map = map_lock.read().map_err(|_| LockPoisoned::Map)?; - - // Get framebuffer and depth buffer - let fb = self.surface_resources.framebuffers.get_next(); - let db = self.surface_resources.depth_buffers.get_next(); - - unsafe { - cmd_buffer.begin_render_pass( - &self.surface_resources.pipeline.renderpass, - fb, - self.surface_resources.pipeline.render_area, - vec![ - RenderAttachmentInfo { - image_view: img_view, - clear_value: ClearValue { - color: ClearColor { - float32: [0.0, 0.0, 0.0, 1.0], - }, - }, - }, - RenderAttachmentInfo { - image_view: &*db.img_view(), - clear_value: ClearValue { - depth_stencil: ClearDepthStencil { - depth: 1.0, - stencil: 0, - }, - }, - }, - ] - .into_iter(), - SubpassContents::Inline, - ); - cmd_buffer.bind_graphics_pipeline(&self.surface_resources.pipeline.pipeline); - - // VP Matrix - let vp = &*(camera_vp.data.as_slice() as *const [f32] as *const [u32]); - - cmd_buffer.push_graphics_constants( - &self.surface_resources.pipeline.pipeline_layout, - ShaderStageFlags::VERTEX, - 0, - vp, - ); - - // Bind buffers - cmd_buffer.bind_vertex_buffers( - 0, - once(( - self.draw_buffers.vertex_buffer.get_buffer(), - SubRange { - offset: 0, - size: None, - }, - )), - ); - cmd_buffer.bind_index_buffer( - self.draw_buffers.index_buffer.get_buffer(), - SubRange { - offset: 0, - size: None, - }, - hal::IndexType::U16, - ); - } - - // Get visible faces - let mut faces = map.get_visible(camera_transform, camera_settings); - - // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once. - let face = faces.next(); - if let Some(face) = face { - let mut face = map.get_face(face).ok_or(LevelError::BadReference)?; - let mut current_chunk = face.texture_idx(&map) as usize / 8; - let mut chunk_start = 0; - - let mut curr_vert_idx: usize = 0; - let mut curr_idx_idx: usize = 0; - loop { - if current_chunk != face.texture_idx(&map) as usize / 8 { - // Last index was last of group, so draw it all if textures are loaded. - self.draw_or_queue( - current_chunk, - cmd_buffer, - chunk_start as u32, - curr_idx_idx as u32, - )?; - - // Next group of same-chunked faces starts here. - chunk_start = curr_idx_idx; - current_chunk = face.texture_idx(&map) as usize / 8; - } - - match face.geometry(&map) { - Geometry::Vertices(v1, v2, v3) => { - for v in &[v1, v2, v3] { - let uvp = - UvPoint(v.position, face.texture_idx(&map).try_into()?, v.tex); - - self.draw_buffers.vertex_buffer[curr_vert_idx] = uvp; - curr_vert_idx += 1; - } - self.draw_buffers.index_buffer[curr_idx_idx] = ( - curr_vert_idx as u16 - 3, - curr_vert_idx as u16 - 2, - curr_vert_idx as u16 - 1, - ); - curr_idx_idx += 1; - } - } - - if curr_vert_idx >= INITIAL_VERT_SIZE.try_into()? - || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()? - { - println!("out of vertex buffer space!"); - break; - } - - match faces.next() { - Some(x) => face = map.get_face(x).ok_or(LevelError::BadReference)?, - None => break, - }; - } - - // Draw the final group of chunks - self.draw_or_queue( - current_chunk, - cmd_buffer, - chunk_start as u32, - curr_idx_idx as u32, - )?; - } - - unsafe { - cmd_buffer.end_render_pass(); - } - - Ok(()) - } - - fn deactivate(self, context: &mut RenderingContext) -> Result<()> { - self.draw_buffers.deactivate(context); - self.surface_resources.deactivate(context)?; - self.repo.deactivate(context); - - Ok(()) - } - - fn handle_surface_change( - mut self, - _session: &Session, - context: &mut RenderingContext, - ) -> Result<Self> { - let new_resources = - SurfaceDependentResources::new::<P>(context, &*self.repo.get_ds_layout()?)?; - let old_resources = self.surface_resources; - self.surface_resources = new_resources; - - match old_resources.deactivate(context) { - Ok(_) => Ok(self), - Err(e) => { - <Self as DrawPass<P>>::deactivate(self, context)?; - Err(e) - } - } - } -} - -impl<'a, M> LevelDrawPass<'a, M> { - fn draw_or_queue( - &mut self, - current_chunk: usize, - cmd_buffer: &mut CommandBufferT, - chunk_start: u32, - curr_idx_idx: u32, - ) -> Result<()> { - if let Some(ds) = self.repo.attempt_get_descriptor_set(current_chunk) { - unsafe { - cmd_buffer.bind_graphics_descriptor_sets( - &*self.surface_resources.pipeline.pipeline_layout, - 0, - once(ds), - empty(), - ); - cmd_buffer.draw_indexed(chunk_start * 3..(curr_idx_idx * 3) + 1, 0, 0..1); - } - } else { - self.repo.queue_load(current_chunk)? - } - - Ok(()) - } -} - -pub struct LevelDrawPassConfig<R> { - pub active_camera: Entity, - pub tex_resolver: R, -} - -impl<'a, M, R, P> IntoDrawPass<LevelDrawPass<'a, M>, P> for LevelDrawPassConfig<R> -where - M: for<'b> MinRenderFeatures<'b> + 'static, - R: TextureResolver + Send + Sync + 'static, - P: PassPosition, -{ - fn init( - self, - _session: &mut Session, - context: &mut RenderingContext, - ) -> Result<LevelDrawPass<'a, M>> { - let repo = TextureRepo::new::<_, TexLoadQueue>( - context, - TextureLoadConfig { - resolver: self.tex_resolver, - filter: Filter::Linear, - wrap_mode: WrapMode::Tile, - }, - ) - .context("Error creating texture repo")?; - let draw_buffers = - DrawBuffers::from_context(context).context("Error creating draw buffers")?; - - let surface_resources = - SurfaceDependentResources::new::<P>(context, &*repo.get_ds_layout()?)?; - - Ok(LevelDrawPass { - repo, - draw_buffers, - active_camera: self.active_camera, - surface_resources, - _d: PhantomData, - }) - } - - fn find_aux_queues( - adapter: &Adapter, - queue_negotiator: &mut QueueFamilyNegotiator, - ) -> Result<()> { - queue_negotiator.find(adapter, &TexLoadQueue, 1)?; - - Ok(()) - } -} - -/// Indicates an issue with the level object being used -#[derive(Debug, Error)] -pub enum LevelError { - #[error("Referential Integrity broken")] - BadReference, -} - -/// Used to store resources which depend on the surface, for convenience in handle_surface_change -struct SurfaceDependentResources { - pub pipeline: CompletePipeline, - pub framebuffers: TargetSpecificResources<FramebufferT>, - pub depth_buffers: TargetSpecificResources<BoundImageView<DepthBufferPool>>, -} - -impl SurfaceDependentResources { - pub fn new<P: PassPosition>( - context: &mut RenderingContext, - ds_layout: &DescriptorSetLayoutT, - ) -> Result<Self> { - let db_spec = ImageSpec { - width: context.properties().extent.width, - height: context.properties().extent.height, - format: context.properties().depth_format, - usage: Usage::DEPTH_STENCIL_ATTACHMENT, - resources: DEPTH_RESOURCES, - }; - let img_count = context.properties().image_count; - - let depth_buffers = TargetSpecificResources::new( - || { - BoundImageView::from_context(context, &db_spec) - .context("Error creating depth buffer") - }, - img_count as usize, - )?; - - let (pipeline, framebuffers) = { - let pipeline_spec = PipelineSpecBuilder::default() - .rasterizer(Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::BACK, - front_face: FrontFace::CounterClockwise, - depth_clamping: false, - depth_bias: None, - conservative: true, - line_width: State::Static(1.0), - }) - .depth_stencil(DepthStencilDesc { - depth: Some(DepthTest { - fun: Comparison::Less, - write: true, - }), - depth_bounds: false, - stencil: None, - }) - .blender(BlendDesc { - logic_op: Some(LogicOp::Copy), - targets: vec![ColorBlendDesc { - mask: ColorMask::ALL, - blend: Some(BlendState { - color: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - alpha: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - }), - }], - }) - .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( - InputAssemblerDesc::new(Primitive::TriangleList), - vec![VertexBufferSpec { - attributes: vec![Format::Rgb32Sfloat, Format::R32Sint, Format::Rg32Sfloat], - rate: VertexInputRate::Vertex, - }], - )) - .shader_vertex(ShaderDesc { - source: include_str!("./data/3d.vert").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Vertex, - }) - .shader_fragment(ShaderDesc { - source: include_str!("./data/3d.frag").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Fragment, - }) - .push_constants(vec![(ShaderStageFlags::VERTEX, 0..64)]) - .renderpass(RenderpassSpec { - colors: vec![AttachmentSpec { - attachment: Attachment { - format: Some(context.properties().color_format), - samples: 1, - ops: P::attachment_ops(), - stencil_ops: P::attachment_ops(), - layouts: P::layout_as_range(), - }, - - used_layout: Layout::ColorAttachmentOptimal, - }], - depth: Some(AttachmentSpec { - attachment: Attachment { - format: Some(context.properties().depth_format), - samples: 1, - ops: AttachmentOps::new( - AttachmentLoadOp::Clear, - AttachmentStoreOp::DontCare, - ), - stencil_ops: AttachmentOps::new( - AttachmentLoadOp::DontCare, - AttachmentStoreOp::DontCare, - ), - layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal, - }, - used_layout: Layout::DepthStencilAttachmentOptimal, - }), - inputs: vec![], - resolves: vec![], - preserves: vec![], - }) - .build() - .context("Error building pipeline")?; - let mut device = context.lock_device()?; - - let pipeline = pipeline_spec - .build(&mut device, context.properties().extent, once(ds_layout)) - .context("Error building pipeline")?; - - let fat = context.properties().swapchain_framebuffer_attachment(); - let dat = FramebufferAttachment { - usage: Usage::DEPTH_STENCIL_ATTACHMENT, - format: context.properties().depth_format, - view_caps: ViewCapabilities::empty(), - }; - - let framebuffers = TargetSpecificResources::new( - || unsafe { - Ok(device.create_framebuffer( - &pipeline.renderpass, - IntoIter::new([fat.clone(), dat.clone()]), - context.properties().extent, - )?) - }, - context.properties().image_count as usize, - )?; - - (pipeline, framebuffers) - }; - - Ok(Self { - pipeline, - framebuffers, - depth_buffers, - }) - } - - pub fn deactivate(self, context: &mut RenderingContext) -> Result<()> { - for db in self.depth_buffers.dissolve() { - db.deactivate_with_context(context); - } - unsafe { - let mut device = context.lock_device()?; - for fb in self.framebuffers.dissolve() { - device.destroy_framebuffer(fb); - } - - self.pipeline.deactivate(&mut device); - } - - Ok(()) - } -} - -fn euler_to_direction(euler: &Vector3) -> Vector3 { - let pitch = euler.x; - let yaw = euler.y; - let _roll = euler.z; // TODO: Support camera roll - - Vector3::new( - yaw.sin() * pitch.cos(), - pitch.sin(), - yaw.cos() * pitch.cos(), - ) -} diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs deleted file mode 100644 index 34f5117..0000000 --- a/stockton-render/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[macro_use] -extern crate legion; -extern crate gfx_hal as hal; -extern crate nalgebra_glm as na; - -pub mod level; -pub mod ui; -pub mod window; diff --git a/stockton-render/src/ui.rs b/stockton-render/src/ui.rs deleted file mode 100644 index 981be02..0000000 --- a/stockton-render/src/ui.rs +++ /dev/null @@ -1,421 +0,0 @@ -//! Minimal code for drawing any level, based on traits from stockton-levels -use crate::window::UiState; - -use stockton_skeleton::{ - buffers::draw::DrawBuffers, - builders::{ - AttachmentSpec, CompletePipeline, PipelineSpecBuilder, RenderpassSpec, ShaderDesc, - VertexBufferSpec, VertexPrimitiveAssemblerSpec, - }, - RenderingContext, - Session, - draw_passes::{util::TargetSpecificResources, DrawPass, IntoDrawPass, PassPosition}, - mem::{DataPool, StagingPool, TexturesPool}, - queue_negotiator::QueueFamilyNegotiator, - texture::{ - TextureResolver, LoadableImage, TexLoadQueue, TextureLoadConfig, TextureRepo, - }, - types::*, -}; - -use std::{ - array::IntoIter, - convert::TryInto, - iter::{empty, once}, - sync::Arc, -}; - -use anyhow::{anyhow, Context, Result}; -use egui::{ClippedMesh, TextureId}; -use egui::{CtxRef, Texture}; -use hal::{ - buffer::SubRange, - command::{ClearColor, ClearValue, RenderAttachmentInfo, SubpassContents}, - format::Format, - image::Layout, - pass::Attachment, - pso::{ - BlendDesc, BlendOp, BlendState, ColorBlendDesc, ColorMask, DepthStencilDesc, Face, Factor, - FrontFace, InputAssemblerDesc, LogicOp, PolygonMode, Primitive, Rasterizer, Rect, - ShaderStageFlags, State, VertexInputRate, - }, -}; -use shaderc::ShaderKind; - -#[derive(Debug)] -pub struct UiPoint(pub Vector2, pub Vector2, pub [f32; 4]); - -/// Draw a Ui object -pub struct UiDrawPass<'a> { - repo: TextureRepo<TexturesPool, StagingPool>, - draw_buffers: DrawBuffers<'a, UiPoint, DataPool, StagingPool>, - - surface_resources: SurfaceDependentResources, -} - -impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { - fn queue_draw( - &mut self, - session: &Session, - img_view: &ImageViewT, - cmd_buffer: &mut CommandBufferT, - ) -> anyhow::Result<()> { - // We might have loaded more textures - self.repo.process_responses(); - - // Make sure we update the vertex buffers after they're written to, but before they're read from. - self.draw_buffers - .vertex_buffer - .record_commit_cmds(cmd_buffer)?; - self.draw_buffers - .index_buffer - .record_commit_cmds(cmd_buffer)?; - - // Get level & camera - let ui: &mut UiState = &mut session.resources.get_mut::<UiState>().unwrap(); - - // Get framebuffer and depth buffer - let fb = self.surface_resources.framebuffers.get_next(); - unsafe { - cmd_buffer.begin_render_pass( - &self.surface_resources.pipeline.renderpass, - fb, - self.surface_resources.pipeline.render_area, - vec![RenderAttachmentInfo { - image_view: img_view, - clear_value: ClearValue { - color: ClearColor { - float32: [0.0, 0.0, 0.0, 1.0], - }, - }, - }] - .into_iter(), - SubpassContents::Inline, - ); - cmd_buffer.bind_graphics_pipeline(&self.surface_resources.pipeline.pipeline); - - // Bind buffers - cmd_buffer.bind_vertex_buffers( - 0, - once(( - self.draw_buffers.vertex_buffer.get_buffer(), - SubRange { - offset: 0, - size: None, - }, - )), - ); - cmd_buffer.bind_index_buffer( - self.draw_buffers.index_buffer.get_buffer(), - SubRange { - offset: 0, - size: None, - }, - hal::IndexType::U16, - ); - } - - let (_out, shapes) = ui.end_frame(); - let screen = ui - .dimensions() - .ok_or_else(|| anyhow!("UI not set up properly."))?; - let shapes = ui.ctx().tessellate(shapes); - - let mut next_idx_idx = 0; - let mut next_vert_idx = 0; - for ClippedMesh(rect, tris) in shapes.iter() { - assert!(tris.texture_id == TextureId::Egui); - - // Copy triangles/indicies - for i in (0..tris.indices.len()).step_by(3) { - self.draw_buffers.index_buffer[next_idx_idx + (i / 3)] = ( - tris.indices[i].try_into()?, - tris.indices[i + 1].try_into()?, - tris.indices[i + 2].try_into()?, - ); - } - - for (i, vertex) in tris.vertices.iter().enumerate() { - self.draw_buffers.vertex_buffer[next_vert_idx + i] = UiPoint( - Vector2::new(vertex.pos.x, vertex.pos.y), - Vector2::new(vertex.uv.x, vertex.uv.y), - [ - vertex.color.r() as f32 / 255.0, - vertex.color.g() as f32 / 255.0, - vertex.color.b() as f32 / 255.0, - vertex.color.a() as f32 / 255.0, - ], - ); - } - - // TODO: *Properly* deal with textures - if let Some(ds) = self.repo.attempt_get_descriptor_set(0) { - unsafe { - cmd_buffer.push_graphics_constants( - &self.surface_resources.pipeline.pipeline_layout, - ShaderStageFlags::VERTEX, - 0, - &[screen.x.to_bits(), screen.y.to_bits()], - ); - - cmd_buffer.set_scissors( - 0, - IntoIter::new([Rect { - x: rect.min.x as i16, - y: rect.min.y as i16, - w: rect.width() as i16, - h: rect.height() as i16, - }]), - ); - cmd_buffer.bind_graphics_descriptor_sets( - &self.surface_resources.pipeline.pipeline_layout, - 0, - IntoIter::new([ds]), - empty(), - ); - // Call draw - cmd_buffer.draw_indexed( - (next_idx_idx as u32 * 3)..((next_idx_idx * 3) + tris.indices.len()) as u32, - next_vert_idx as i32, - 0..1, - ); - } - } else { - self.repo.queue_load(0)?; - } - - next_idx_idx += tris.indices.len() / 3; - next_vert_idx += tris.vertices.len(); - } - - unsafe { - cmd_buffer.end_render_pass(); - } - - Ok(()) - } - - fn deactivate(self, context: &mut RenderingContext) -> Result<()> { - self.draw_buffers.deactivate(context); - self.surface_resources.deactivate(context)?; - self.repo.deactivate(context); - - Ok(()) - } - - fn handle_surface_change( - mut self, - _session: &Session, - context: &mut RenderingContext, - ) -> Result<Self> { - let new_surface_resources = - SurfaceDependentResources::new::<P>(context, &*self.repo.get_ds_layout()?)?; - let old_surface_resources = self.surface_resources; - self.surface_resources = new_surface_resources; - - match old_surface_resources.deactivate(context) { - Ok(_) => Ok(self), - Err(e) => { - <Self as DrawPass<P>>::deactivate(self, context)?; - Err(e) - } - } - } -} - -impl<'a, P: PassPosition> IntoDrawPass<UiDrawPass<'a>, P> for () { - fn init(self, session: &mut Session, context: &mut RenderingContext) -> Result<UiDrawPass<'a>> { - let ui: &mut UiState = &mut session.resources.get_mut::<UiState>().unwrap(); - let repo = TextureRepo::new::<_, TexLoadQueue>( - context, - TextureLoadConfig { - resolver: UiTextures::new(ui.ctx().clone()), - filter: hal::image::Filter::Linear, - wrap_mode: hal::image::WrapMode::Clamp, - }, - ) - .context("Error creating texture repo")?; - - let draw_buffers = - DrawBuffers::from_context(context).context("Error creating draw buffers")?; - - let surface_resources = - SurfaceDependentResources::new::<P>(context, &*repo.get_ds_layout()?)?; - - Ok(UiDrawPass { - repo, - draw_buffers, - surface_resources, - }) - } - - fn find_aux_queues( - adapter: &Adapter, - queue_negotiator: &mut QueueFamilyNegotiator, - ) -> Result<()> { - queue_negotiator.find(adapter, &TexLoadQueue, 1)?; - - Ok(()) - } -} - -pub struct UiTexture(Arc<Texture>); - -pub struct UiTextures { - ctx: CtxRef, -} - -impl TextureResolver for UiTextures { - type Image = UiTexture; - fn resolve(&mut self, tex: u32) -> Option<Self::Image> { - if tex == 0 { - Some(UiTexture(self.ctx.texture())) - } else { - None - } - } -} - -impl UiTextures { - pub fn new(ctx: CtxRef) -> Self { - UiTextures { ctx } - } -} - -impl LoadableImage for UiTexture { - fn width(&self) -> u32 { - self.0.width as u32 - } - fn height(&self) -> u32 { - self.0.height as u32 - } - unsafe fn copy_row(&self, y: u32, ptr: *mut u8) { - let row_size = self.0.width as u32; - let pixels = &self.0.pixels[(y * row_size) as usize..((y + 1) * row_size) as usize]; - - for (i, x) in pixels.iter().enumerate() { - *ptr.offset(i as isize * 4) = 255; - *ptr.offset((i as isize * 4) + 1) = 255; - *ptr.offset((i as isize * 4) + 2) = 255; - *ptr.offset((i as isize * 4) + 3) = *x; - } - } -} - -struct SurfaceDependentResources { - pipeline: CompletePipeline, - framebuffers: TargetSpecificResources<FramebufferT>, -} - -impl SurfaceDependentResources { - fn new<P: PassPosition>( - context: &mut RenderingContext, - ds_layout: &DescriptorSetLayoutT, - ) -> Result<Self> { - let mut device = context.lock_device()?; - - let spec = PipelineSpecBuilder::default() - .rasterizer(Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::NONE, - front_face: FrontFace::CounterClockwise, - depth_clamping: false, - depth_bias: None, - conservative: true, - line_width: State::Static(1.0), - }) - .depth_stencil(DepthStencilDesc { - depth: None, - depth_bounds: false, - stencil: None, - }) - .blender(BlendDesc { - logic_op: Some(LogicOp::Copy), - targets: vec![ColorBlendDesc { - mask: ColorMask::ALL, - blend: Some(BlendState { - color: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - alpha: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - }), - }], - }) - .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( - InputAssemblerDesc::new(Primitive::TriangleList), - vec![VertexBufferSpec { - attributes: vec![Format::Rg32Sfloat, Format::Rg32Sfloat, Format::Rgba32Sfloat], - rate: VertexInputRate::Vertex, - }], - )) - .shader_vertex(ShaderDesc { - source: include_str!("./data/ui.vert").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Vertex, - }) - .shader_fragment(ShaderDesc { - source: include_str!("./data/ui.frag").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Fragment, - }) - .push_constants(vec![(ShaderStageFlags::VERTEX, 0..8)]) - .renderpass(RenderpassSpec { - colors: vec![AttachmentSpec { - attachment: Attachment { - format: Some(context.properties().color_format), - samples: 1, - ops: P::attachment_ops(), - stencil_ops: P::attachment_ops(), - layouts: P::layout_as_range(), - }, - used_layout: Layout::ColorAttachmentOptimal, - }], - depth: None, - inputs: vec![], - resolves: vec![], - preserves: vec![], - }) - .dynamic_scissor(true) - .build() - .context("Error building pipeline")?; - - let pipeline = spec - .build(&mut device, context.properties().extent, once(ds_layout)) - .context("Error building pipeline")?; - - let fat = context.properties().swapchain_framebuffer_attachment(); - - let framebuffers = TargetSpecificResources::new( - || unsafe { - Ok(device.create_framebuffer( - &pipeline.renderpass, - IntoIter::new([fat.clone()]), - context.properties().extent, - )?) - }, - context.properties().image_count as usize, - )?; - - Ok(Self { - framebuffers, - pipeline, - }) - } - - fn deactivate(self, context: &mut RenderingContext) -> Result<()> { - unsafe { - let mut device = context.lock_device()?; - self.pipeline.deactivate(&mut device); - - for fb in self.framebuffers.dissolve() { - device.destroy_framebuffer(fb); - } - } - - Ok(()) - } -} diff --git a/stockton-render/src/window.rs b/stockton-render/src/window.rs deleted file mode 100644 index 429a3c2..0000000 --- a/stockton-render/src/window.rs +++ /dev/null @@ -1,278 +0,0 @@ -use stockton_input::{Action as KBAction, InputManager, Mouse}; -use stockton_skeleton::{ - draw_passes::{DrawPass, Singular}, - Renderer, -}; - -use std::sync::{ - mpsc::{channel, Receiver, Sender}, - Arc, RwLock, -}; - -use egui::{CtxRef, Event, Modifiers, Output, Pos2, RawInput, Rect, Vec2}; -use epaint::ClippedShape; -use legion::systems::Runnable; -use log::debug; -use winit::{ - event::{ElementState, Event as WinitEvent, MouseButton, WindowEvent as WinitWindowEvent}, - event_loop::ControlFlow, -}; - -#[derive(Debug, Clone, Copy)] -pub enum WindowEvent { - SizeChanged(u32, u32), - CloseRequested, - KeyboardAction(KBAction), - MouseAction(KBAction), - MouseMoved(f32, f32), - MouseLeft, -} - -impl WindowEvent { - pub fn from(winit_event: &WinitEvent<()>) -> Option<WindowEvent> { - // TODO - match winit_event { - WinitEvent::WindowEvent { event, .. } => match event { - WinitWindowEvent::CloseRequested => Some(WindowEvent::CloseRequested), - 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, - ))), - ElementState::Released => Some(WindowEvent::KeyboardAction( - KBAction::KeyRelease(input.scancode), - )), - }, - WinitWindowEvent::CursorMoved { position, .. } => Some(WindowEvent::MouseMoved( - 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, - } - } -} - -pub struct UiState { - ctx: CtxRef, - raw_input: RawInput, - frame_active: bool, - - modifiers: Modifiers, - pointer_pos: Pos2, -} - -impl UiState { - pub fn populate_initial_state<T: DrawPass<Singular>>(&mut self, renderer: &Renderer<T>) { - let props = renderer.context().properties(); - self.set_dimensions(props.extent.width, props.extent.height); - self.set_pixels_per_point(Some(renderer.context().pixels_per_point())); - debug!("{:?}", self.raw_input); - } - - #[inline] - pub fn ctx(&mut self) -> &CtxRef { - if !self.frame_active { - self.begin_frame() - } - &self.ctx - } - - #[inline] - fn begin_frame(&mut self) { - #[allow(deprecated)] - let new_raw_input = RawInput { - scroll_delta: Vec2::new(0.0, 0.0), - zoom_delta: 0.0, - screen_size: self.raw_input.screen_size, - screen_rect: self.raw_input.screen_rect, - pixels_per_point: self.raw_input.pixels_per_point, - time: self.raw_input.time, - predicted_dt: self.raw_input.predicted_dt, - modifiers: self.modifiers, - events: Vec::new(), - }; - self.ctx.begin_frame(self.raw_input.take()); - self.raw_input = new_raw_input; - self.frame_active = true; - } - - #[inline] - pub(crate) fn end_frame(&mut self) -> (Output, Vec<ClippedShape>) { - self.frame_active = false; - self.ctx.end_frame() - } - - #[inline] - pub fn dimensions(&self) -> Option<egui::math::Vec2> { - Some(self.raw_input.screen_rect?.size()) - } - - fn set_mouse_pos(&mut self, x: f32, y: f32) { - self.raw_input - .events - .push(Event::PointerMoved(Pos2::new(x, y))); - - self.pointer_pos = Pos2::new(x, y); - } - - fn set_mouse_left(&mut self) { - self.raw_input.events.push(Event::PointerGone); - } - - fn set_dimensions(&mut self, w: u32, h: u32) { - self.raw_input.screen_rect = - Some(Rect::from_x_y_ranges(0.0..=(w as f32), 0.0..=(h as f32))); - } - fn set_pixels_per_point(&mut self, ppp: Option<f32>) { - debug!("Using {:?} pixels per point", ppp); - self.raw_input.pixels_per_point = ppp; - } - - fn handle_action(&mut self, action: KBAction) { - // TODO - match action { - KBAction::MousePress(btn) => { - self.raw_input.events.push(Event::PointerButton { - pos: self.pointer_pos, - button: match btn { - stockton_input::MouseButton::Left => egui::PointerButton::Primary, - stockton_input::MouseButton::Right => egui::PointerButton::Secondary, - stockton_input::MouseButton::Middle => egui::PointerButton::Middle, - stockton_input::MouseButton::Other(_) => todo!(), - }, - pressed: true, - modifiers: self.modifiers, - }); - } - KBAction::MouseRelease(btn) => { - self.raw_input.events.push(Event::PointerButton { - pos: self.pointer_pos, - button: match btn { - stockton_input::MouseButton::Left => egui::PointerButton::Primary, - stockton_input::MouseButton::Right => egui::PointerButton::Secondary, - stockton_input::MouseButton::Middle => egui::PointerButton::Middle, - stockton_input::MouseButton::Other(_) => todo!(), - }, - pressed: false, - modifiers: self.modifiers, - }); - } - _ => (), - } - } -} - -impl Default for UiState { - fn default() -> Self { - UiState { - ctx: CtxRef::default(), - raw_input: RawInput::default(), - frame_active: false, - modifiers: Default::default(), - pointer_pos: Pos2::new(0.0, 0.0), - } - } -} - -pub struct WindowFlow { - window_events: Receiver<WindowEvent>, - update_control_flow: Arc<RwLock<ControlFlow>>, -} - -impl WindowFlow { - pub fn new(update_control_flow: Arc<RwLock<ControlFlow>>) -> (Self, Sender<WindowEvent>) { - let (tx, rx) = channel(); - ( - Self { - window_events: rx, - update_control_flow, - }, - tx, - ) - } -} - -#[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] window_channel: &mut WindowFlow, - #[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; - let mut mouse_delta = mouse.abs; - - while let Ok(event) = window_channel.window_events.try_recv() { - match event { - WindowEvent::SizeChanged(w, h) => { - ui_state.set_dimensions(w, h); - } - WindowEvent::CloseRequested => { - let mut flow = window_channel.update_control_flow.write().unwrap(); - // TODO: Let everything know this is our last frame - *flow = ControlFlow::Exit; - } - WindowEvent::KeyboardAction(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); - } - 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); - } - }; - } - - mouse.handle_frame(mouse_delta); - - manager.handle_frame(&actions_buf[0..actions_buf_cursor]); -} - -pub fn process_window_events_system<T: 'static + InputManager>() -> impl Runnable { - _process_window_events_system::<T>(Vec::with_capacity(4)) -} |