use glam::Mat4;
use ready_paint::scene::{get_res, get_res_mut, return_res, HashTypeId2Data, Pass, Ready, Update};
use wgpu::util::DeviceExt;
use crate::world::World;
#[derive(Default)]
pub struct Tetrahedron {
vertices: Option<[[f32; 3]; 4]>,
object_buffer: Option<wgpu::Buffer>,
object_line_index_buffer: Option<wgpu::Buffer>,
pipeline: Option<wgpu::RenderPipeline>,
}
impl Ready for Tetrahedron {
fn ready(&mut self, data: &mut HashTypeId2Data, gfx: &ready_paint::gfx::Gfx) {
let vertices: [[f32; 3]; 4] = [
[0.0, 1., 0.0],
[-1., -1., -1.],
[1., -1., -1.],
[0.0, -1., 1.],
];
let object_buffer = gfx
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Object Buffer"),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
});
let vertex_layout = wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x3,
offset: 0,
shader_location: 0,
}],
};
let object_line_index_buffer =
gfx.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Object Line Index Buffer"),
contents: bytemuck::cast_slice(&[0u16, 1, 1, 2, 2, 0, 0, 3, 1, 3, 2, 3]),
usage: wgpu::BufferUsages::INDEX,
});
let shader = gfx
.device
.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("screen shader"),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(SHADER)),
});
let world = get_res::<World>(data);
let world_pipeline_layout =
gfx.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("World Pipeline Layout"),
bind_group_layouts: &[world.uniforms_bind_group_layout.as_ref().unwrap()],
push_constant_ranges: &[],
});
let object_pipeline = gfx
.device
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Object Pipeline"),
layout: Some(&world_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[vertex_layout],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
compilation_options: Default::default(),
entry_point: Some("fs_main"),
targets: &[Some(
gfx.surface_config.as_ref().unwrap().view_formats[0].into(),
)],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::LineList,
front_face: wgpu::FrontFace::Cw,
cull_mode: Some(wgpu::Face::Back),
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
});
return_res(
data,
Tetrahedron {
vertices: Some(vertices),
object_buffer: Some(object_buffer),
object_line_index_buffer: Some(object_line_index_buffer),
pipeline: Some(object_pipeline),
},
);
}
}
impl<'a> Pass<'a> for Tetrahedron {
fn pass(
data: &mut HashTypeId2Data,
render_pass: &'a mut wgpu::RenderPass<'a>,
) -> &'a mut wgpu::RenderPass<'a> {
let tetra = get_res::<Tetrahedron>(data);
render_pass.set_pipeline(tetra.pipeline.as_ref().unwrap());
render_pass.set_vertex_buffer(0, tetra.object_buffer.as_ref().unwrap().slice(..));
render_pass.set_index_buffer(
tetra.object_line_index_buffer.as_ref().unwrap().slice(..),
wgpu::IndexFormat::Uint16,
);
render_pass.draw_indexed(0..12, 0, 0..1);
render_pass
}
}
impl Update for Tetrahedron {
fn update(data: &mut HashTypeId2Data, gfx: &ready_paint::gfx::Gfx) {
let tetra = get_res_mut::<Self>(data);
let buffer = tetra.object_buffer.as_ref().unwrap();
let dt = gfx.delta_time;
let rotation_speed = std::f32::consts::PI;
let rotation = Mat4::from_rotation_y(rotation_speed * dt);
let rotated_vertices = tetra.vertices.as_ref().unwrap().map(|v| {
let v = rotation.transform_point3(glam::Vec3::from(v));
[v.x, v.y, v.z]
});
tetra.vertices = Some(rotated_vertices);
gfx.queue.write_buffer(
buffer,
0,
bytemuck::cast_slice(rotated_vertices.as_flattened()),
);
}
}
const SHADER: &str = r#"
struct Uniforms {
matrix: mat4x4<f32>,
resolution: vec2<f32>,
delta_time: f32,
_padding: f32,
}
@group(0) @binding(0)
var<uniform> uniforms: Uniforms;
@vertex
fn vs_main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return uniforms.matrix * vec4<f32>(pos, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 1.0, 1.0, 1.0);
}
"#;