diff --git a/src/camera.rs b/src/camera.rs index d4f778d..36a9a01 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -4,9 +4,9 @@ use std::time::{Duration, Instant}; use cgmath::{Decomposed, InnerSpace, Matrix4, Point3, Rad, Vector3}; use winit_24::dpi::{LogicalPosition, PhysicalPosition}; use winit_24::event::{ElementState, MouseScrollDelta, VirtualKeyCode}; - use crate::render::OPENGL_TO_WGPU_MATRIX; + #[derive(Clone, Copy, Debug, PartialEq)] pub struct Camera { pub position: Point3, diff --git a/src/light.rs b/src/light.rs index 987bb24..03017e0 100644 --- a/src/light.rs +++ b/src/light.rs @@ -1,10 +1,10 @@ use bytemuck::__core::ops::Range; use bytemuck::{Zeroable, Pod}; use cgmath::Point3; -use crate::render::OPENGL_TO_WGPU_MATRIX; use std::sync::Arc; use wgpu::TextureView; use crate::components::{RangeCopy, Position}; +use crate::render::OPENGL_TO_WGPU_MATRIX; #[repr(C)] diff --git a/src/main.rs b/src/main.rs index f127969..fa2ad44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,8 +49,7 @@ use crate::components::{Collider, Color, ImguiWindow, LoopState, Physics, Positi use crate::imgui_supp::extended_winit_imgui_support; use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; use crate::owned_event::{OwnedEvent, OwnedEventExtension}; -use crate::physics::PhysicsState; -use crate::render::Renderer; +use crate::physics::state::PhysicsState; mod camera; mod components; @@ -99,17 +98,17 @@ fn main() { let mut world = World::default(); let mut imgui_prepare_schedule = Schedule::builder() - .add_system(render::imgui_prepare_system()) + .add_system(render::system::imgui_prepare_system()) .build(); let mut render_schedule = Schedule::builder() - .add_system(render::render_test_system()) + .add_system(render::system::render_test_system()) .build(); let mut update_schedule = Schedule::builder() - .add_system(physics::update_camera_system()) - .add_system(physics::run_physics_system()) - .add_system(physics::update_models_system()) + .add_system(physics::system::update_camera_system()) + .add_system(physics::system::run_physics_system()) + .add_system(physics::system::update_models_system()) // next system here, gamelogic update system? .build(); @@ -156,7 +155,7 @@ fn main() { imgui_context.context.set_ini_filename(None); // The renderer - let mut renderer = render::Renderer::init(&window, &mut imgui_context); + let mut renderer = render::state::RenderState::init(&window, &mut imgui_context); entity_loading(&mut world, &mut renderer); resources.insert(renderer); @@ -286,7 +285,7 @@ fn main() { let height = size.height; resources - .get_mut::() + .get_mut::() .unwrap() .resize(width, height); } @@ -309,7 +308,7 @@ fn main() { }); } -pub fn entity_loading(world: &mut World, renderer: &mut Renderer) { +pub fn entity_loading(world: &mut World, renderer: &mut render::state::RenderState) { let monkey_mesh = renderer.load_mesh_to_buffer("./resources/monkey.obj"); diff --git a/src/physics/mod.rs b/src/physics/mod.rs new file mode 100644 index 0000000..48b1f7b --- /dev/null +++ b/src/physics/mod.rs @@ -0,0 +1,2 @@ +pub mod state; +pub mod system; \ No newline at end of file diff --git a/src/physics/state.rs b/src/physics/state.rs new file mode 100644 index 0000000..a41cf44 --- /dev/null +++ b/src/physics/state.rs @@ -0,0 +1,41 @@ +use std::time::Instant; + +use cgmath::{Euler, Quaternion}; +use legion::world::SubWorld; +use legion::IntoQuery; +use legion::*; +use nalgebra::Quaternion as naQuaternion; +use rapier3d::dynamics::{IntegrationParameters, JointSet, RigidBodySet}; +use rapier3d::geometry::{BroadPhase, ColliderSet, NarrowPhase}; +use rapier3d::pipeline::PhysicsPipeline; + +use crate::camera::{Camera, CameraController}; +use crate::components::{Collider, LoopState, Mesh, Physics, Position}; +use imgui::FontSource; + +pub struct PhysicsState { + pub(in crate::physics) gravity: rapier3d::math::Vector, + pub(in crate::physics) integration_parameters: IntegrationParameters, + pub(in crate::physics) broad_phase: BroadPhase, + pub(in crate::physics) narrow_phase: NarrowPhase, + pub(in crate::physics) bodies: RigidBodySet, + pub(in crate::physics) colliders: ColliderSet, + pub(in crate::physics) joints: JointSet, +} + +impl PhysicsState { + pub fn build(gravity: rapier3d::math::Vector) -> (PhysicsPipeline, PhysicsState) { + ( + PhysicsPipeline::new(), + PhysicsState { + gravity, + integration_parameters: IntegrationParameters::default(), + broad_phase: BroadPhase::new(), + narrow_phase: NarrowPhase::new(), + bodies: RigidBodySet::new(), + colliders: ColliderSet::new(), + joints: JointSet::new(), + }, + ) + } +} diff --git a/src/physics.rs b/src/physics/system.rs similarity index 80% rename from src/physics.rs rename to src/physics/system.rs index f22b04f..3e5ed62 100644 --- a/src/physics.rs +++ b/src/physics/system.rs @@ -11,35 +11,9 @@ use rapier3d::pipeline::PhysicsPipeline; use crate::camera::{Camera, CameraController}; use crate::components::{Collider, LoopState, Mesh, Physics, Position}; -use crate::render::{EntityUniforms, Renderer}; use imgui::FontSource; +use crate::physics::state::PhysicsState; -pub struct PhysicsState { - gravity: rapier3d::math::Vector, - integration_parameters: IntegrationParameters, - broad_phase: BroadPhase, - narrow_phase: NarrowPhase, - bodies: RigidBodySet, - colliders: ColliderSet, - joints: JointSet, -} - -impl PhysicsState { - pub fn build(gravity: rapier3d::math::Vector) -> (PhysicsPipeline, PhysicsState) { - ( - PhysicsPipeline::new(), - PhysicsState { - gravity, - integration_parameters: IntegrationParameters::default(), - broad_phase: BroadPhase::new(), - narrow_phase: NarrowPhase::new(), - bodies: RigidBodySet::new(), - colliders: ColliderSet::new(), - joints: JointSet::new(), - }, - ) - } -} #[system] #[write_component(Collider)] diff --git a/src/render/mod.rs b/src/render/mod.rs new file mode 100644 index 0000000..9a54a83 --- /dev/null +++ b/src/render/mod.rs @@ -0,0 +1,68 @@ +use wgpu::CommandEncoder; +use bytemuck::{Pod, Zeroable}; + +pub mod state; +pub mod system; + + +#[cfg_attr(rustfmt, rustfmt_skip)] +#[allow(unused)] +pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.0, 0.0, 0.5, 1.0, +); + + +// I dont even wanna talk about this +lazy_static! { + static ref INTEL_DEBUG_SHINANIGANS : bool = std::env::var("INTEL_FIX").map_or(false, |a| true); +} + +fn insert_debug_marker_checked(name: &str, command_encoder: &mut CommandEncoder) { + if !*INTEL_DEBUG_SHINANIGANS { + command_encoder.insert_debug_marker(name); + } +} + +fn push_debug_group_checked(name: &str, command_encoder: &mut CommandEncoder) { + if !*INTEL_DEBUG_SHINANIGANS { + command_encoder.push_debug_group(name); + } +} + +fn pop_debug_group_checked(command_encoder: &mut CommandEncoder) { + if !*INTEL_DEBUG_SHINANIGANS { + command_encoder.pop_debug_group(); + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct ForwardUniforms { + proj: [[f32; 4]; 4], + num_lights: [u32; 4], +} + +unsafe impl Pod for ForwardUniforms {} +unsafe impl Zeroable for ForwardUniforms {} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct EntityUniforms { + model: [[f32; 4]; 4], + color: [f32; 4], +} + +unsafe impl Pod for EntityUniforms {} +unsafe impl Zeroable for EntityUniforms {} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct ShadowUniforms { + proj: [[f32; 4]; 4], +} + +unsafe impl Pod for ShadowUniforms {} +unsafe impl Zeroable for ShadowUniforms {} \ No newline at end of file diff --git a/src/render.rs b/src/render/state.rs similarity index 71% rename from src/render.rs rename to src/render/state.rs index acec043..91c8cb4 100644 --- a/src/render.rs +++ b/src/render/state.rs @@ -29,334 +29,48 @@ use crate::current_ui; use crate::geometry::{import_mesh, vertex, Vertex}; use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; use crate::light::{DirectionalLight, LightRaw}; +use crate::render::{EntityUniforms, ShadowUniforms, ForwardUniforms}; -#[cfg_attr(rustfmt, rustfmt_skip)] -#[allow(unused)] -pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.0, - 0.0, 0.0, 0.5, 1.0, -); - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct ForwardUniforms { - proj: [[f32; 4]; 4], - num_lights: [u32; 4], -} - -unsafe impl Pod for ForwardUniforms {} -unsafe impl Zeroable for ForwardUniforms {} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub struct EntityUniforms { - model: [[f32; 4]; 4], - color: [f32; 4], -} - -unsafe impl Pod for EntityUniforms {} -unsafe impl Zeroable for EntityUniforms {} - -#[repr(C)] -#[derive(Clone, Copy, Debug)] -pub struct ShadowUniforms { - proj: [[f32; 4]; 4], -} - -unsafe impl Pod for ShadowUniforms {} -unsafe impl Zeroable for ShadowUniforms {} /// A render pass consists of a pipeline, bindgroup, and uniform buf /// The uniform buf is just the ShadowUniforms or ForwardUniforms /// And the bindgroup is just the localbindgroup (the EntityUniforms) and the rest pub struct Pass { - pipeline: wgpu::RenderPipeline, - bind_group: wgpu::BindGroup, - uniform_buf: wgpu::Buffer, + pub pipeline: wgpu::RenderPipeline, + pub bind_group: wgpu::BindGroup, + pub uniform_buf: wgpu::Buffer, } -#[system] -#[write_component(Camera)] -pub fn imgui_prepare( - world: &mut SubWorld, - #[resource] winit_window: &mut Window, - #[resource] imgui_context: &mut Arc>, - #[resource] imgui_platform: &mut Arc>, -) { - let mut imgui_context = &mut imgui_context.lock().unwrap().context; - let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform; - - //imgui_state.context.io_mut().update_delta_time(Duration::new(0,160)); - imgui_platform - .prepare_frame(imgui_context.io_mut(), &winit_window) - .expect("Failed to prepare frame"); - - // get the frame and build a ui window - unsafe { crate::CURRENT_UI = Some(std::mem::transmute(imgui_context.frame())) } - - -} -#[system] -#[write_component(Camera)] -#[write_component(Position)] -#[write_component(Point3)] -#[write_component(Mesh)] -#[write_component(Color)] -#[write_component(DirectionalLight)] -pub fn render_test( - world: &mut SubWorld, - #[resource] renderer: &mut Renderer, - #[resource] winit_window: &mut Window, - #[resource] imgui_context: &mut Arc>, - #[resource] imgui_platform: &mut Arc>, -) { - let mut encoder = renderer - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - push_debug_group_checked("start render function", &mut encoder); - - - let frame = renderer.get_current_frame(); - - // Update the camera uniform buffers, need to make it support selection of - // cameras - let mut query = <(&mut Camera)>::query(); - for (camera) in query.iter_mut(world) { - let matrix = camera.calc_matrix(renderer.camera_projection); - let mx_ref: &[f32; 16] = matrix.as_ref(); - renderer.queue.write_buffer( - &renderer.forward_pass.uniform_buf, - 0, - bytemuck::cast_slice(mx_ref), - ); - } - - let mut query = <(&mut Position, &mut Mesh, &mut Color)>::query(); - let mut mesh_stack = Vec::new(); - - // Update the entity uniforms - for (pos, mesh, color) in query.iter_mut(world) { - let d = Decomposed { - scale: 1.0, - rot: Quaternion::from(pos.rot), - disp: Vector3::new(pos.x, pos.y, pos.z), - }; - let m = Matrix4::from(d); - let data = EntityUniforms { - model: m.into(), - color: [ - color.r as f32, - color.g as f32, - color.b as f32, - color.a as f32, - ], - }; - renderer - .queue - .write_buffer(&mesh.uniform_buffer, 0, bytemuck::bytes_of(&data)); - - mesh_stack.push(mesh.clone()); - } - - if renderer.lights_are_dirty { - renderer.lights_are_dirty = false; - let mut query = <(&mut DirectionalLight, &mut Point3)>::query(); - for (i, (light, pos)) in query.iter_mut(world).enumerate() { - renderer.queue.write_buffer( - &renderer.light_uniform_buf, - (i * mem::size_of::()) as wgpu::BufferAddress, - bytemuck::bytes_of(&light.to_raw()), - ); - } - } - - push_debug_group_checked("shadow passes", &mut encoder); - - let mut query = <(&mut DirectionalLight, &mut Point3)>::query(); - - for (i, (light, pos)) in query.iter_mut(world).enumerate() { - insert_debug_marker_checked(&format!("shadow pass {} (light at position {:?})", i, pos), &mut encoder); +pub struct RenderState { - // The light uniform buffer already has the projection, - // let's just copy it over to the shadow uniform buffer. - encoder.copy_buffer_to_buffer( - &renderer.light_uniform_buf, - (i * mem::size_of::()) as wgpu::BufferAddress, - &renderer.shadow_pass.uniform_buf, - 0, - 64, - ); - - insert_debug_marker_checked("render entities", &mut encoder); - - - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("render pass"), - color_attachments: &[], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &light.target_view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: true, - }), - stencil_ops: None, - }), - }); - pass.set_pipeline(&renderer.shadow_pass.pipeline); - pass.set_bind_group(0, &renderer.shadow_pass.bind_group, &[]); - - for mesh in &mesh_stack { - pass.set_bind_group(1, &mesh.bind_group, &[]); - // TODO, pipe through this index format through the mesh - pass.set_index_buffer(mesh.index_buffer.slice(..), mesh.index_format); - pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); - pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); - } - } - pop_debug_group_checked(&mut encoder); - // forward pass - push_debug_group_checked("forward rendering pass", &mut encoder); - - { - let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("forward render pass"), - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.output.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.1, - g: 0.2, - b: 0.3, - a: 1.0, - }), - store: true, - }, - }], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &renderer.forward_depth, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: false, - }), - stencil_ops: None, - }), - }); - pass.set_pipeline(&renderer.forward_pass.pipeline); - pass.set_bind_group(0, &renderer.forward_pass.bind_group, &[]); - - let mut query = <(&mut Position, &mut Mesh, &mut Color)>::query(); - - for (pos, mesh, color) in query.iter_mut(world) { - pass.set_bind_group(1, &mesh.bind_group, &[]); - // TODO: Pipe this in through the mesh - pass.set_index_buffer(mesh.index_buffer.slice(..), mesh.index_format); - pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); - pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); - } - } - pop_debug_group_checked(&mut encoder); - pop_debug_group_checked(&mut encoder); - - { - let mut imgui_context = &mut imgui_context.lock().unwrap().context; - let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform; - - //imgui_state.context.io_mut().update_delta_time(Duration::new(0,160)); - let ui = unsafe { crate::current_ui().unwrap() }; - - let window = imgui::Window::new(im_str!("Hello too")); - window - .size([400.0, 100.0], Condition::FirstUseEver) - .position([50.0, 50.0], Condition::FirstUseEver) - .build(&ui, || { - ui.text(im_str!("Frametime: {:?}", 10.0)); - }); - - // ui.show_demo_window(&mut true); - imgui_platform.prepare_render(&ui, &winit_window); - - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.output.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, - }], - depth_stencil_attachment: None, - }); - - // We gotta do some jank shit here and manually pull the draw data from the UI - let draw_data = unsafe { - crate::CURRENT_UI = None; // This is where the drop() occurs - imgui::sys::igRender(); - &*(imgui::sys::igGetDrawData() as *mut imgui::DrawData) - }; - - renderer - .imgui_renderer - .render(draw_data, &renderer.queue, &renderer.device, &mut rpass) - .expect("Rendering failed"); - } - - renderer.queue.submit(iter::once(encoder.finish())); -} -lazy_static! { - static ref INTEL_DEBUG_SHINANIGANS : bool = std::env::var("INTEL_FIX").map_or(false, |a| true); -} - -fn insert_debug_marker_checked(name: &str, command_encoder: &mut CommandEncoder) { - if !*INTEL_DEBUG_SHINANIGANS { - command_encoder.insert_debug_marker(name); - } -} - -fn push_debug_group_checked(name: &str, command_encoder: &mut CommandEncoder) { - if !*INTEL_DEBUG_SHINANIGANS { - command_encoder.push_debug_group(name); - } -} - -fn pop_debug_group_checked(command_encoder: &mut CommandEncoder) { - if !*INTEL_DEBUG_SHINANIGANS { - command_encoder.pop_debug_group(); - } -} - -pub struct Renderer { swapchain: SwapChain, swapchain_description: SwapChainDescriptor, instance: Arc, - device: Arc, - queue: Arc, + pub(in crate::render) device: Arc, + pub(in crate::render) queue: Arc, size: PhysicalSize, surface: Arc, - lights_are_dirty: bool, - shadow_pass: Pass, + pub(in crate::render) lights_are_dirty: bool, + pub(in crate::render) shadow_pass: Pass, shadow_target_views: Vec>, views_given: u32, - forward_pass: Pass, - forward_depth: wgpu::TextureView, + pub(in crate::render) forward_pass: Pass, + pub(in crate::render) forward_depth: wgpu::TextureView, entity_bind_group_layout: BindGroupLayout, - light_uniform_buf: wgpu::Buffer, + pub(in crate::render) light_uniform_buf: wgpu::Buffer, - camera_projection: Matrix4, + pub(in crate::render) camera_projection: Matrix4, - imgui_renderer: ImguiRenderer, + pub(in crate::render) imgui_renderer: ImguiRenderer, } -impl Renderer { +impl RenderState { const MAX_LIGHTS: usize = 10; const SHADOW_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; const SHADOW_SIZE: wgpu::Extent3d = wgpu::Extent3d { @@ -459,7 +173,7 @@ impl Renderer { pub fn load_mesh_to_buffer(&self, filepath: &str) -> Mesh { let (vertices, indices) = import_mesh(filepath); let index_count = indices.len(); - let (vertex_buf, index_buf) = Renderer::create_buffer(&self.device, indices, vertices); + let (vertex_buf, index_buf) = RenderState::create_buffer(&self.device, indices, vertices); let uniform_size = mem::size_of::() as wgpu::BufferAddress; @@ -494,7 +208,7 @@ impl Renderer { } } - pub fn init(window: &Window, imgui_context: &mut ImguiContext) -> Renderer { + pub fn init(window: &Window, imgui_context: &mut ImguiContext) -> RenderState { // Grab the GPU instance, and query its features let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); let (size, surface) = unsafe { @@ -510,8 +224,8 @@ impl Renderer { }); let adapter = futures::executor::block_on(adapter).unwrap(); - let optional_features = Renderer::optional_features(); - let required_features = Renderer::required_features(); + let optional_features = RenderState::optional_features(); + let required_features = RenderState::required_features(); let adapter_features = adapter.features(); let needed_limits = wgpu::Limits::default(); //Renderer::required_limits(); @@ -635,9 +349,9 @@ impl Renderer { // Create the render pipeline let vs_module = - device.create_shader_module(&wgpu::include_spirv!("../resources/bake.vert.spv")); + device.create_shader_module(&wgpu::include_spirv!("../../resources/bake.vert.spv")); let fs_module = - device.create_shader_module(&wgpu::include_spirv!("../resources/bake.frag.spv")); + device.create_shader_module(&wgpu::include_spirv!("../../resources/bake.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("shadow"), @@ -849,9 +563,9 @@ impl Renderer { // Create the render pipeline let vs_module = - device.create_shader_module(&wgpu::include_spirv!("../resources/forward.vert.spv")); + device.create_shader_module(&wgpu::include_spirv!("../../resources/forward.vert.spv")); let fs_module = - device.create_shader_module(&wgpu::include_spirv!("../resources/forward.frag.spv")); + device.create_shader_module(&wgpu::include_spirv!("../../resources/forward.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("main"), @@ -911,7 +625,7 @@ impl Renderer { let mut imgui_renderer = ImguiRenderer::new(&mut imgui_context.context, &device, &queue, renderer_config); - Renderer { + RenderState { swapchain: swap_chain, queue: queue, size, @@ -973,3 +687,10 @@ impl Renderer { self.camera_projection = mx_total; } } + + +/* + + + + */ \ No newline at end of file diff --git a/src/render/system.rs b/src/render/system.rs new file mode 100644 index 0000000..6f4dae0 --- /dev/null +++ b/src/render/system.rs @@ -0,0 +1,265 @@ +use std::cell::RefCell; +use std::sync::{Arc, Mutex}; +use std::thread::current; +use std::time::Duration; +use std::{iter, num::NonZeroU32, ops::Range, rc::Rc}; + +use bytemuck::__core::mem; +use bytemuck::{Pod, Zeroable}; +use cgmath::{ + vec3, Decomposed, Deg, Euler, InnerSpace, Matrix4, Point3, Quaternion, Rad, Rotation3, + Transform, Vector3, +}; +use futures::executor::LocalPool; +use imgui::sys::ImGuiContext; +use imgui::*; +use imgui_wgpu::{Renderer as ImguiRenderer, RendererConfig as ImguiRendererConfig}; +use legion::world::SubWorld; +use legion::*; +use rapier3d::parry::motion::RigidMotionComposition; +use wgpu::util::DeviceExt; +use wgpu::{BackendBit, BindGroup, BindGroupLayout, Buffer, BufferBindingType, Device, FragmentState, Instance, Queue, Surface, SwapChain, SwapChainDescriptor, SwapChainFrame, TextureView, VertexState, CommandEncoder}; +use winit_24::dpi::PhysicalSize; +use winit_24::platform::unix::x11::ffi::Time; +use winit_24::window::Window; + +use crate::camera::{Camera, CameraController}; +use crate::components::{Color, Mesh, Position, RangeCopy}; +use crate::current_ui; +use crate::geometry::{import_mesh, vertex, Vertex}; +use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; +use crate::light::{DirectionalLight, LightRaw}; +use crate::render::state::{RenderState}; +use crate::render::{push_debug_group_checked, insert_debug_marker_checked, pop_debug_group_checked, EntityUniforms}; + + +#[system] +#[write_component(Camera)] +pub fn imgui_prepare( + world: &mut SubWorld, + #[resource] winit_window: &mut Window, + #[resource] imgui_context: &mut Arc>, + #[resource] imgui_platform: &mut Arc>, +) { + let mut imgui_context = &mut imgui_context.lock().unwrap().context; + let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform; + + //imgui_state.context.io_mut().update_delta_time(Duration::new(0,160)); + imgui_platform + .prepare_frame(imgui_context.io_mut(), &winit_window) + .expect("Failed to prepare frame"); + + // get the frame and build a ui window + unsafe { crate::CURRENT_UI = Some(std::mem::transmute(imgui_context.frame())) } +} +#[system] +#[write_component(Camera)] +#[write_component(Position)] +#[write_component(Point3)] +#[write_component(Mesh)] +#[write_component(Color)] +#[write_component(DirectionalLight)] +pub fn render_test( + world: &mut SubWorld, + #[resource] renderer: &mut RenderState, + #[resource] winit_window: &mut Window, + #[resource] imgui_context: &mut Arc>, + #[resource] imgui_platform: &mut Arc>, +) { + let mut encoder = renderer + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + push_debug_group_checked("start render function", &mut encoder); + + + let frame = renderer.get_current_frame(); + + // Update the camera uniform buffers, need to make it support selection of + // cameras + let mut query = <(&mut Camera)>::query(); + for (camera) in query.iter_mut(world) { + let matrix = camera.calc_matrix(renderer.camera_projection); + let mx_ref: &[f32; 16] = matrix.as_ref(); + renderer.queue.write_buffer( + &renderer.forward_pass.uniform_buf, + 0, + bytemuck::cast_slice(mx_ref), + ); + } + + let mut query = <(&mut Position, &mut Mesh, &mut Color)>::query(); + let mut mesh_stack = Vec::new(); + + // Update the entity uniforms + for (pos, mesh, color) in query.iter_mut(world) { + let d = Decomposed { + scale: 1.0, + rot: Quaternion::from(pos.rot), + disp: Vector3::new(pos.x, pos.y, pos.z), + }; + let m = Matrix4::from(d); + let data = EntityUniforms { + model: m.into(), + color: [ + color.r as f32, + color.g as f32, + color.b as f32, + color.a as f32, + ], + }; + renderer + .queue + .write_buffer(&mesh.uniform_buffer, 0, bytemuck::bytes_of(&data)); + + mesh_stack.push(mesh.clone()); + } + + if renderer.lights_are_dirty { + renderer.lights_are_dirty = false; + let mut query = <(&mut DirectionalLight, &mut Point3)>::query(); + for (i, (light, pos)) in query.iter_mut(world).enumerate() { + renderer.queue.write_buffer( + &renderer.light_uniform_buf, + (i * mem::size_of::()) as wgpu::BufferAddress, + bytemuck::bytes_of(&light.to_raw()), + ); + } + } + + push_debug_group_checked("shadow passes", &mut encoder); + + let mut query = <(&mut DirectionalLight, &mut Point3)>::query(); + + for (i, (light, pos)) in query.iter_mut(world).enumerate() { + insert_debug_marker_checked(&format!("shadow pass {} (light at position {:?})", i, pos), &mut encoder); + + + // The light uniform buffer already has the projection, + // let's just copy it over to the shadow uniform buffer. + encoder.copy_buffer_to_buffer( + &renderer.light_uniform_buf, + (i * mem::size_of::()) as wgpu::BufferAddress, + &renderer.shadow_pass.uniform_buf, + 0, + 64, + ); + + insert_debug_marker_checked("render entities", &mut encoder); + + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("render pass"), + color_attachments: &[], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &light.target_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }), + }); + pass.set_pipeline(&renderer.shadow_pass.pipeline); + pass.set_bind_group(0, &renderer.shadow_pass.bind_group, &[]); + + for mesh in &mesh_stack { + pass.set_bind_group(1, &mesh.bind_group, &[]); + // TODO, pipe through this index format through the mesh + pass.set_index_buffer(mesh.index_buffer.slice(..), mesh.index_format); + pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); + } + } + + pop_debug_group_checked(&mut encoder); + // forward pass + push_debug_group_checked("forward rendering pass", &mut encoder); + + { + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("forward render pass"), + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.output.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }), + store: true, + }, + }], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &renderer.forward_depth, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: false, + }), + stencil_ops: None, + }), + }); + pass.set_pipeline(&renderer.forward_pass.pipeline); + pass.set_bind_group(0, &renderer.forward_pass.bind_group, &[]); + + let mut query = <(&mut Position, &mut Mesh, &mut Color)>::query(); + + for (pos, mesh, color) in query.iter_mut(world) { + pass.set_bind_group(1, &mesh.bind_group, &[]); + // TODO: Pipe this in through the mesh + pass.set_index_buffer(mesh.index_buffer.slice(..), mesh.index_format); + pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); + pass.draw_indexed(0..mesh.index_count as u32, 0, 0..1); + } + } + pop_debug_group_checked(&mut encoder); + pop_debug_group_checked(&mut encoder); + + { + let mut imgui_context = &mut imgui_context.lock().unwrap().context; + let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform; + + //imgui_state.context.io_mut().update_delta_time(Duration::new(0,160)); + let ui = unsafe { crate::current_ui().unwrap() }; + + let window = imgui::Window::new(im_str!("Hello too")); + window + .size([400.0, 100.0], Condition::FirstUseEver) + .position([50.0, 50.0], Condition::FirstUseEver) + .build(&ui, || { + ui.text(im_str!("Frametime: {:?}", 10.0)); + }); + + // ui.show_demo_window(&mut true); + imgui_platform.prepare_render(&ui, &winit_window); + + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.output.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, + }, + }], + depth_stencil_attachment: None, + }); + + // We gotta do some jank shit here and manually pull the draw data from the UI + let draw_data = unsafe { + crate::CURRENT_UI = None; // This is where the drop() occurs + imgui::sys::igRender(); + &*(imgui::sys::igGetDrawData() as *mut imgui::DrawData) + }; + + renderer + .imgui_renderer + .render(draw_data, &renderer.queue, &renderer.device, &mut rpass) + .expect("Rendering failed"); + } + + renderer.queue.submit(iter::once(encoder.finish())); +}