diff options
Diffstat (limited to 'stockton-render/src/level.rs')
-rw-r--r-- | stockton-render/src/level.rs | 554 |
1 files changed, 0 insertions, 554 deletions
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(), - ) -} |