@ -8,14 +8,15 @@ use futures::executor::LocalPool;
use legion ::world ::SubWorld ;
use legion ::* ;
use wgpu ::util ::DeviceExt ;
use wgpu ::{ B uffer, Device , Instance , Queue , Surface , SwapChain , SwapChainDescriptor , SwapChainFrame , BindGroup, BindGroupLayout } ;
use wgpu ::{ B indGroup, BindGroupLayout , B uffer, Device , Instance , Queue , Surface , SwapChain , SwapChainDescriptor , SwapChainFrame , TextureView } ;
use winit ::dpi ::PhysicalSize ;
use winit ::platform ::unix ::x11 ::ffi ::Time ;
use winit ::window ::Window ;
use crate ::geometry ::{ create_plane , import_mesh , Vertex } ;
use crate ::light ::LightRaw ;
use crate ::{ Color , Mesh , Position , Velocity , OPENGL_TO_WGPU_MATRIX } ;
use crate ::{ Color , DirectionalLight , Mesh , Position , RangeCopy , Velocity , OPENGL_TO_WGPU_MATRIX } ;
#[ repr(C) ]
#[ derive(Clone, Copy) ]
@ -67,8 +68,9 @@ pub struct Renderer {
forward_depth : wgpu ::TextureView ,
entity_bind_group_layout : BindGroupLayout ,
light_uniform_buf: wgpu ::Buffer ,
shadow_target_views: Vec < Arc < TextureView > > ,
light_uniform_buf : wgpu ::Buffer ,
}
impl Renderer {
@ -93,26 +95,12 @@ impl Renderer {
}
}
/*
SOOOOOOOOOOOOooo .. . Legion systems have to be standalone functions , which is fine
we can do a special kind of song and dance
Main loop {
renderer
runtime
render_system ( param1 , 2 , 3 , renderer ) ;
animation_system ( param1 , 2 , 3 , runtime ) ;
renderer . finalize ( )
}
* /
#[ system ]
#[ write_component(Position) ]
#[ write_component(Point3<f32>) ]
#[ write_component(Mesh) ]
#[ write_component(Color) ]
#[ write_component(DirectionalLight) ]
pub fn render_test ( world : & mut SubWorld , #[ resource ] renderer : & mut Renderer ) {
let frame = renderer . get_current_frame ( ) ;
@ -120,11 +108,8 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) {
// Update the entity uniforms
for ( pos , mesh , color ) in query . iter_mut ( world ) {
// Revolve the entity by the rotation speed, only if it is non-zero
// if vel.rs != 0.0 {
// let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(vel.rs));
// pos.mx = pos.mx * rotation;
// }
let rotation = cgmath ::Matrix4 ::from_angle_x ( cgmath ::Deg ( 1.0 ) ) ;
pos . mx = pos . mx * rotation ;
let data = EntityUniforms {
model : pos . mx . into ( ) ,
@ -140,66 +125,78 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) {
. write_buffer ( & mesh . uniform_buffer , 0 , bytemuck ::bytes_of ( & data ) ) ;
}
// if self.lights_are_dirty {
// self.lights_are_dirty = false;
// for (i, light) in self.lights.iter().enumerate() {
// queue.write_buffer(
// &self.light_uniform_buf,
// (i * mem::size_of::<LightRaw>()) as wgpu::BufferAddress,
// bytemuck::bytes_of(&light.to_raw()),
// );
// }
// }
if renderer . lights_are_dirty {
renderer . lights_are_dirty = false ;
let mut query = < ( & mut DirectionalLight , & mut Position ) > ::query ( ) ;
for ( i , ( light , pos ) ) in query . iter_mut ( world ) . enumerate ( ) {
renderer . queue . write_buffer (
& renderer . light_uniform_buf ,
( i * mem ::size_of ::< LightRaw > ( ) ) as wgpu ::BufferAddress ,
bytemuck ::bytes_of ( & light . to_raw ( * pos ) ) ,
) ;
}
}
let mut encoder = renderer
. device
. create_command_encoder ( & wgpu ::CommandEncoderDescriptor { label : None } ) ;
encoder . push_debug_group ( "shadow passes" ) ;
/* for (i, light) in self.lights.iter().enumerate() {
let mut query = < ( & mut DirectionalLight , & mut Point3 < f32 > ) > ::query ( ) ;
let mut light_stack = Vec ::new ( ) ;
for ( i , ( light , pos ) ) in query . iter_mut ( world ) . enumerate ( ) {
light_stack . push ( light . clone ( ) ) ;
encoder . push_debug_group ( & format! (
"shadow pass {} (light at position {:?})" ,
i , light . pos
i , pos
) ) ;
// The light uniform buffer already has the projection,
// let's just copy it over to the shadow uniform buffer.
encoder . copy_buffer_to_buffer (
& self . light_uniform_buf ,
& renderer . light_uniform_buf ,
( i * mem ::size_of ::< LightRaw > ( ) ) as wgpu ::BufferAddress ,
& self . shadow_pass . uniform_buf ,
& renderer . shadow_pass . uniform_buf ,
0 ,
64 ,
) ;
encoder . pop_debug_group ( ) ;
}
for light in light_stack {
encoder . insert_debug_marker ( "render entities" ) ;
{
let mut pass = encoder . begin_render_pass ( & wgpu ::RenderPassDescriptor {
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 ,
} ,
) ,
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 ( & self . shadow_pass . pipeline ) ;
pass . set_bind_group ( 0 , & self . shadow_pass . bind_group , & [ ] ) ;
for entity in & self . entities {
pass . set_bind_group ( 1 , & entity . bind_group , & [ ] ) ;
pass . set_index_buffer ( entity . index_buf . slice ( .. ) ) ;
pass . set_vertex_buffer ( 0 , entity . vertex_buf . slice ( .. ) ) ;
pass . draw_indexed ( 0 .. entity . index_count as u32 , 0 , 0 .. 1 ) ;
pass . set_pipeline ( & renderer . shadow_pass . pipeline ) ;
pass . set_bind_group ( 0 , & renderer . shadow_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 , & [ ] ) ;
pass . set_index_buffer ( mesh . index_buffer . slice ( .. ) ) ;
pass . set_vertex_buffer ( 0 , mesh . vertex_buffer . slice ( .. ) ) ;
pass . draw_indexed ( 0 .. mesh . index_count as u32 , 0 , 0 .. 1 ) ;
}
}
}
encoder . pop_debug_group ( ) ;
} * /
encoder . pop_debug_group ( ) ;
// forward pass
@ -258,7 +255,6 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) {
}
impl Renderer {
pub fn get_current_frame ( & mut self ) -> SwapChainFrame {
// Update the renderers swapchain state
match self . swapchain . get_current_frame ( ) {
@ -299,25 +295,28 @@ impl Renderer {
} ) ,
) ;
// // Creates the vertex and index buffers for the plane
// let (plane_vertex_data, plane_index_data) = create_plane(7.0);
// self.plane_vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
// label: Some("Plane Vertex Buffer"),
// contents: bytemuck::cast_slice(&plane_vertex_data),
// usage: wgpu::BufferUsage::VERTEX,
// });
//
// self.plane_index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
// label: Some("Plane Index Buffer"),
// contents: bytemuck::cast_slice(&plane_index_data),
// usage: wgpu::BufferUsage::INDEX,
// });
// Creates the uniform for entities, which does the rotation and projection
( vertex_buf , index_buf )
}
pub fn create_light ( & self ) -> DirectionalLight {
let target = self . shadow_target_views . get ( 0 ) . take ( ) . unwrap ( ) ;
DirectionalLight {
color : wgpu ::Color {
r : 1.0 ,
g : 0.5 ,
b : 0.5 ,
a : 1.0 ,
} ,
fov : 45.0 ,
depth : RangeCopy {
start : 1.0 ,
end : 20.0 ,
} ,
target_view : target . clone ( )
}
}
pub fn load_mesh_to_buffer ( & self , filepath : & str ) -> Mesh {
let ( vertices , indices ) = import_mesh ( filepath ) ;
let index_count = indices . len ( ) ;
@ -370,11 +369,6 @@ impl Renderer {
let optional_features = Renderer ::optional_features ( ) ;
let required_features = Renderer ::required_features ( ) ;
let adapter_features = adapter . features ( ) ;
// assert!(
// adapter_features.contains(required_features),
// "Adapter does not support required features for this example: {:?}",
// required_features - adapter_features
// );
let needed_limits = wgpu ::Limits ::default ( ) ; //Renderer::required_limits();
@ -453,19 +447,6 @@ impl Renderer {
mapped_at_creation : false ,
} ) ;
// Pre init the light uniform, with slots enough for MAX_LIGHTS
let light_uniform_size =
( Self ::MAX_LIGHTS * mem ::size_of ::< LightRaw > ( ) ) as wgpu ::BufferAddress ;
let light_uniform_buf = device . create_buffer ( & wgpu ::BufferDescriptor {
label : None ,
size : light_uniform_size ,
usage : wgpu ::BufferUsage ::UNIFORM
| wgpu ::BufferUsage ::COPY_SRC
| wgpu ::BufferUsage ::COPY_DST ,
mapped_at_creation : false ,
} ) ;
// This seems way way way way easier than what I was doing in tracer
// Though the attr thing is still a macro. Which would cause issues if
// I wanted to get tricky with the 0,1 types
@ -494,7 +475,6 @@ impl Renderer {
} ] ,
} ) ;
/*
There appear to be two passes required for shadows , the shadow pass , and the forward pass
Need to open this up in renderdoc and see what it ' s actually doing
@ -592,6 +572,44 @@ impl Renderer {
}
} ;
// Pre init the light uniform, with slots enough for MAX_LIGHTS
let light_uniform_size =
( Self ::MAX_LIGHTS * mem ::size_of ::< LightRaw > ( ) ) as wgpu ::BufferAddress ;
let light_uniform_buf = device . create_buffer ( & wgpu ::BufferDescriptor {
label : None ,
size : light_uniform_size ,
usage : wgpu ::BufferUsage ::UNIFORM
| wgpu ::BufferUsage ::COPY_SRC
| wgpu ::BufferUsage ::COPY_DST ,
mapped_at_creation : false ,
} ) ;
let shadow_texture = device . create_texture ( & wgpu ::TextureDescriptor {
size : Self ::SHADOW_SIZE ,
mip_level_count : 1 ,
sample_count : 1 ,
dimension : wgpu ::TextureDimension ::D2 ,
format : Self ::SHADOW_FORMAT ,
usage : wgpu ::TextureUsage ::OUTPUT_ATTACHMENT | wgpu ::TextureUsage ::SAMPLED ,
label : None ,
} ) ;
let mut shadow_target_views = ( 0 .. 2 )
. map ( | i | {
Arc ::new ( shadow_texture . create_view ( & wgpu ::TextureViewDescriptor {
label : Some ( "shadow" ) ,
format : None ,
dimension : Some ( wgpu ::TextureViewDimension ::D2 ) ,
aspect : wgpu ::TextureAspect ::All ,
base_mip_level : 0 ,
level_count : None ,
base_array_layer : i as u32 ,
array_layer_count : NonZeroU32 ::new ( 1 ) ,
} ) )
} )
. collect ::< Vec < _ > > ( ) ;
let forward_pass = {
// Create pipeline layout
let bind_group_layout =
@ -660,30 +678,7 @@ impl Renderer {
usage : wgpu ::BufferUsage ::UNIFORM | wgpu ::BufferUsage ::COPY_DST ,
} ) ;
let shadow_texture = device . create_texture ( & wgpu ::TextureDescriptor {
size : Self ::SHADOW_SIZE ,
mip_level_count : 1 ,
sample_count : 1 ,
dimension : wgpu ::TextureDimension ::D2 ,
format : Self ::SHADOW_FORMAT ,
usage : wgpu ::TextureUsage ::OUTPUT_ATTACHMENT | wgpu ::TextureUsage ::SAMPLED ,
label : None ,
} ) ;
let mut shadow_target_views = ( 0 .. 2 )
. map ( | i | {
Some ( shadow_texture . create_view ( & wgpu ::TextureViewDescriptor {
label : Some ( "shadow" ) ,
format : None ,
dimension : Some ( wgpu ::TextureViewDimension ::D2 ) ,
aspect : wgpu ::TextureAspect ::All ,
base_mip_level : 0 ,
level_count : None ,
base_array_layer : i as u32 ,
array_layer_count : NonZeroU32 ::new ( 1 ) ,
} ) )
} )
. collect ::< Vec < _ > > ( ) ;
// shadow_target_views[0].take().unwrap(),
// pub(crate) target_view: wgpu::TextureView,
@ -796,142 +791,12 @@ impl Renderer {
forward_pass ,
forward_depth : depth_texture . create_view ( & wgpu ::TextureViewDescriptor ::default ( ) ) ,
entity_bind_group_layout : entity_bind_group_layout ,
shadow_target_views : shadow_target_views ,
light_uniform_buf ,
swapchain_description : sc_desc ,
surface ,
instance : Arc ::new ( instance ) ,
}
}
pub fn render (
& mut self ,
frame : & wgpu ::SwapChainTexture ,
device : & wgpu ::Device ,
queue : & wgpu ::Queue ,
_spawner : & impl futures ::task ::LocalSpawn ,
) {
// update uniforms
// for entity in self.entities.iter_mut() {
//
// // Revolve the entity by the rotation speed, only if it is non-zero
// if entity.rotation_speed != 0.0 {
// let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(entity.rotation_speed));
// entity.mx_world = entity.mx_world * rotation;
// }
//
// let data = EntityUniforms {
// model: entity.mx_world.into(),
// color: [
// entity.color.r as f32,
// entity.color.g as f32,
// entity.color.b as f32,
// entity.color.a as f32,
// ],
// };
// queue.write_buffer(&entity.uniform_buf, 0, bytemuck::bytes_of(&data));
// }
// if self.lights_are_dirty {
// self.lights_are_dirty = false;
// for (i, light) in self.lights.iter().enumerate() {
// queue.write_buffer(
// &self.light_uniform_buf,
// (i * mem::size_of::<LightRaw>()) as wgpu::BufferAddress,
// bytemuck::bytes_of(&light.to_raw()),
// );
// }
// }
let mut encoder =
device . create_command_encoder ( & wgpu ::CommandEncoderDescriptor { label : None } ) ;
encoder . push_debug_group ( "shadow passes" ) ;
/* for (i, light) in self.lights.iter().enumerate() {
encoder . push_debug_group ( & format! (
"shadow pass {} (light at position {:?})" ,
i , light . pos
) ) ;
// The light uniform buffer already has the projection,
// let's just copy it over to the shadow uniform buffer.
encoder . copy_buffer_to_buffer (
& self . light_uniform_buf ,
( i * mem ::size_of ::< LightRaw > ( ) ) as wgpu ::BufferAddress ,
& self . shadow_pass . uniform_buf ,
0 ,
64 ,
) ;
encoder . insert_debug_marker ( "render entities" ) ;
{
let mut pass = encoder . begin_render_pass ( & wgpu ::RenderPassDescriptor {
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 ( & self . shadow_pass . pipeline ) ;
pass . set_bind_group ( 0 , & self . shadow_pass . bind_group , & [ ] ) ;
for entity in & self . entities {
pass . set_bind_group ( 1 , & entity . bind_group , & [ ] ) ;
pass . set_index_buffer ( entity . index_buf . slice ( .. ) ) ;
pass . set_vertex_buffer ( 0 , entity . vertex_buf . slice ( .. ) ) ;
pass . draw_indexed ( 0 .. entity . index_count as u32 , 0 , 0 .. 1 ) ;
}
}
encoder . pop_debug_group ( ) ;
} * /
encoder . pop_debug_group ( ) ;
// forward pass
encoder . push_debug_group ( "forward rendering pass" ) ;
{
let mut pass = encoder . begin_render_pass ( & wgpu ::RenderPassDescriptor {
color_attachments : & [ wgpu ::RenderPassColorAttachmentDescriptor {
attachment : & frame . 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 : & self . forward_depth ,
depth_ops : Some ( wgpu ::Operations {
load : wgpu ::LoadOp ::Clear ( 1.0 ) ,
store : false ,
} ) ,
stencil_ops : None ,
} ) ,
} ) ;
pass . set_pipeline ( & self . forward_pass . pipeline ) ;
pass . set_bind_group ( 0 , & self . forward_pass . bind_group , & [ ] ) ;
// for entity in &self.entities {
// pass.set_bind_group(1, &entity.bind_group, &[]);
// pass.set_index_buffer(entity.index_buf.slice(..));
// pass.set_vertex_buffer(0, entity.vertex_buf.slice(..));
// pass.draw_indexed(0..entity.index_count as u32, 0, 0..1);
// }
}
encoder . pop_debug_group ( ) ;
queue . submit ( iter ::once ( encoder . finish ( ) ) ) ;
}
pub ( crate ) fn required_features ( ) -> wgpu ::Features {