#[path = "../framework.rs"]
mod framework;
use bytemuck::{Pod, Zeroable};
use simple_wgpu::{
BindGroup, BindGroupBuilder, Buffer, ColorAttachment, ColorTargetState, CommandEncoder,
Context, DrawCall, RasteriserState, RenderPipeline, RenderPipelineBuilder, RenderTexture,
Shader, Texture, VertexBufferLayout,
};
use std::{f32::consts, future::Future, mem, pin::Pin, task};
use wgpu::include_wgsl;
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
struct Vertex {
_pos: [f32; 4],
_tex_coord: [f32; 2],
}
fn vertex(pos: [i8; 3], tc: [i8; 2]) -> Vertex {
Vertex {
_pos: [pos[0] as f32, pos[1] as f32, pos[2] as f32, 1.0],
_tex_coord: [tc[0] as f32, tc[1] as f32],
}
}
fn create_vertices() -> (Vec<Vertex>, Vec<u16>) {
let vertex_data = [
vertex([-1, -1, 1], [0, 0]),
vertex([1, -1, 1], [1, 0]),
vertex([1, 1, 1], [1, 1]),
vertex([-1, 1, 1], [0, 1]),
vertex([-1, 1, -1], [1, 0]),
vertex([1, 1, -1], [0, 0]),
vertex([1, -1, -1], [0, 1]),
vertex([-1, -1, -1], [1, 1]),
vertex([1, -1, -1], [0, 0]),
vertex([1, 1, -1], [1, 0]),
vertex([1, 1, 1], [1, 1]),
vertex([1, -1, 1], [0, 1]),
vertex([-1, -1, 1], [1, 0]),
vertex([-1, 1, 1], [0, 0]),
vertex([-1, 1, -1], [0, 1]),
vertex([-1, -1, -1], [1, 1]),
vertex([1, 1, -1], [1, 0]),
vertex([-1, 1, -1], [0, 0]),
vertex([-1, 1, 1], [0, 1]),
vertex([1, 1, 1], [1, 1]),
vertex([1, -1, 1], [0, 0]),
vertex([-1, -1, 1], [1, 0]),
vertex([-1, -1, -1], [1, 1]),
vertex([1, -1, -1], [0, 1]),
];
let index_data: &[u16] = &[
0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4, 8, 9, 10, 10, 11, 8, 12, 13, 14, 14, 15, 12, 16, 17, 18, 18, 19, 16, 20, 21, 22, 22, 23, 20, ];
(vertex_data.to_vec(), index_data.to_vec())
}
fn create_texels(size: usize) -> Vec<u8> {
(0..size * size)
.map(|id| {
let cx = 3.0 * (id % size) as f32 / (size - 1) as f32 - 2.0;
let cy = 2.0 * (id / size) as f32 / (size - 1) as f32 - 1.0;
let (mut x, mut y, mut count) = (cx, cy, 0);
while count < 0xFF && x * x + y * y < 4.0 {
let old_x = x;
x = x * x - y * y + cx;
y = 2.0 * old_x * y + cy;
count += 1;
}
count
})
.collect()
}
struct ErrorFuture<F> {
inner: F,
}
impl<F: Future<Output = Option<wgpu::Error>>> Future for ErrorFuture<F> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<()> {
let inner = unsafe { self.map_unchecked_mut(|me| &mut me.inner) };
inner.poll(cx).map(|error| {
if let Some(e) = error {
panic!("Rendering {e}");
}
})
}
}
struct Example {
vertex_buf: Buffer,
index_buf: Buffer,
index_count: usize,
bind_group: BindGroup,
uniform_buf: Buffer,
pipeline: RenderPipeline,
pipeline_wire: Option<RenderPipeline>,
}
impl Example {
fn generate_matrix(aspect_ratio: f32) -> glam::Mat4 {
let projection = glam::Mat4::perspective_rh(consts::FRAC_PI_4, aspect_ratio, 1.0, 10.0);
let view = glam::Mat4::look_at_rh(
glam::Vec3::new(1.5f32, -5.0, 3.0),
glam::Vec3::ZERO,
glam::Vec3::Z,
);
projection * view
}
}
impl framework::Example for Example {
fn init(
config: &wgpu::SurfaceConfiguration,
_adapter: &wgpu::Adapter,
context: &Context,
) -> Self {
let vertex_size = mem::size_of::<Vertex>();
let (vertex_data, index_data) = create_vertices();
let vertex_buf = Buffer::with_data(
Some("Vertex Buffer"),
wgpu::BufferUsages::VERTEX,
bytemuck::cast_slice(&vertex_data),
context,
);
let index_buf = Buffer::with_data(
Some("Index Buffer"),
wgpu::BufferUsages::INDEX,
bytemuck::cast_slice(&index_data),
context,
);
let size = 256u32;
let texels = create_texels(size as usize);
let texture_extent = wgpu::Extent3d {
width: size,
height: size,
depth_or_array_layers: 1,
};
let texture = Texture::with_data(
&wgpu::TextureDescriptor {
label: None,
size: texture_extent,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R8Uint,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
},
&texels,
Some(size),
context,
);
let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32);
let mx_ref: &[f32; 16] = mx_total.as_ref();
let uniform_buf = Buffer::with_data(
Some("Uniform Buffer"),
wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
bytemuck::cast_slice(mx_ref),
context,
);
let bind_group = BindGroupBuilder::new()
.buffer(
0,
wgpu::ShaderStages::VERTEX,
&uniform_buf.uniform_binding(),
None,
)
.texture(1, wgpu::ShaderStages::FRAGMENT, &texture.texture_binding())
.build();
let shader = Shader::new(include_wgsl!("shader.wgsl"), context);
let vertex_buffers = [VertexBufferLayout {
array_stride: vertex_size as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: vec![
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x4,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: 4 * 4,
shader_location: 1,
},
],
}];
let pipeline = RenderPipelineBuilder::with_vertex(
&shader.entry_point("vs_main"),
vertex_buffers.clone(),
)
.fragment(&shader.entry_point("fs_main"), [Some(Default::default())])
.build();
let pipeline_wire = if context
.device()
.features()
.contains(wgt::Features::POLYGON_MODE_LINE)
{
let pipeline_wire =
RenderPipelineBuilder::with_vertex(&shader.entry_point("vs_main"), vertex_buffers)
.fragment(
&shader.entry_point("fs_main"),
[Some(ColorTargetState {
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
operation: wgpu::BlendOperation::Add,
src_factor: wgpu::BlendFactor::SrcAlpha,
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
},
alpha: wgpu::BlendComponent::REPLACE,
}),
write_mask: wgpu::ColorWrites::ALL,
})],
)
.build();
Some(pipeline_wire)
} else {
None
};
Example {
vertex_buf,
index_buf,
index_count: index_data.len(),
bind_group,
uniform_buf,
pipeline,
pipeline_wire,
}
}
fn update(&mut self, _event: winit::event::WindowEvent) {
}
fn resize(&mut self, config: &wgpu::SurfaceConfiguration, context: &Context) {
let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32);
let mx_ref: &[f32; 16] = mx_total.as_ref();
self.uniform_buf
.write(bytemuck::cast_slice(mx_ref), context);
}
fn render(&mut self, target: &RenderTexture, context: &Context) {
context
.device()
.push_error_scope(wgpu::ErrorFilter::Validation);
let mut frame = CommandEncoder::new(None, &context);
{
let mut rpass = frame.render_pass(
None,
vec![ColorAttachment {
target: target.clone(),
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: wgt::StoreOp::Store,
},
}],
None,
Some(Default::default()),
);
rpass.draw(DrawCall {
bind_groups: vec![self.bind_group.clone()],
bind_group_offsets: vec![vec![]],
pipeline: self.pipeline.clone(),
vertices: vec![self.vertex_buf.slice(..)],
indices: Some(self.index_buf.slice(..)),
element_range: 0..self.index_count,
instance_range: 0..1,
rasteriser_state: RasteriserState {
cull_mode: Some(wgpu::Face::Back),
..Default::default()
},
});
if let Some(ref pipe) = self.pipeline_wire {
rpass.draw(DrawCall {
bind_groups: vec![self.bind_group.clone()],
bind_group_offsets: vec![vec![]],
pipeline: pipe.clone(),
vertices: vec![self.vertex_buf.slice(..)],
indices: Some(self.index_buf.slice(..)),
element_range: 0..self.index_count,
instance_range: 0..1,
rasteriser_state: RasteriserState {
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Line,
..Default::default()
},
});
}
}
}
}
fn main() {
framework::run::<Example>("cube");
}