Reset repo

This commit is contained in:
Guilherme Werner
2024-02-16 19:03:26 -03:00
parent b0c04c6f7b
commit 47f2244d1d
48 changed files with 13 additions and 2092 deletions

View File

@ -1,2 +0,0 @@
[build]
target-dir = "Binaries"

View File

@ -10,3 +10,6 @@ insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.env*]
insert_final_newline = false

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
Binaries/
target/
Cargo.lock

View File

@ -1,34 +1,19 @@
[package]
name = "renderer"
version = "0.0.1"
description = "WGPU Renderer"
description = "Renderer"
repository = "https://github.com/GuilhermeWerner/Renderer"
license = "MIT"
edition = "2021"
publish = false
[lib]
name = "Graphics"
name = "renderer"
crate-type = ["rlib"]
path = "Source/lib.rs"
path = "src/lib.rs"
[[example]]
name = "Cubes"
path = "Examples/Cubes.rs"
[[example]]
name = "Triangle"
path = "Examples/Triangle.rs"
[[bin]]
name = "renderer"
path = "src/main.rs"
[dependencies]
anyhow = "1.0"
bytemuck = { version = "1.4", features = [ "derive" ] }
cgmath = "0.18"
env_logger = "0.9"
image = "0.24.1"
log = "0.4"
pollster = "0.2"
serde = { version = "1.0", features = ["derive"] }
tobj = "3.0"
wgpu ={ git = "https://github.com/GuilhermeWerner/wgpu" }
winit = "0.26.1"

View File

@ -1,14 +0,0 @@
# Blender MTL File: 'Cube.blend'
# Material Count: 1
newmtl Material
Ns 323.999994
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Bump T_Normal.png
map_Kd T_White.png

View File

@ -1,41 +0,0 @@
# Blender v2.93.1 OBJ File: 'Cube.blend'
# www.blender.org
mtllib SM_Cube.mtl
o Cube
v 1.000000 1.000000 -1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 1.000000 1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.125000 0.750000
vn 0.0000 1.0000 0.0000
vn 0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 0.0000
vn 0.0000 -1.0000 -0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
g Cube_Cube_Material
usemtl Material
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 4/4/2 3/6/2 6/7/2
f 6/8/3 3/9/3 2/10/3 7/11/3
f 7/12/4 8/13/4 5/5/4 6/14/4
f 8/13/5 1/1/5 4/4/5 5/5/5
f 7/11/6 2/10/6 1/1/6 8/13/6

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -1,316 +0,0 @@
#![allow(non_snake_case)]
#![allow(unused_variables)]
use anyhow::Result;
use cgmath::prelude::*;
use std::path::PathBuf;
use std::time::Duration;
use wgpu::util::DeviceExt;
use winit::event::*;
use Graphics::Camera::*;
use Graphics::Render::*;
use Graphics::{Display, Runtime, State};
struct Cubes {
render_pipeline: wgpu::RenderPipeline,
obj_model: Model,
camera: Camera,
camera_controller: CameraController,
camera_uniform: CameraUniform,
camera_buffer: wgpu::Buffer,
camera_bind_group: wgpu::BindGroup,
instances: Vec<Instance>,
instance_buffer: wgpu::Buffer,
depth_texture: Texture,
}
impl State for Cubes {
fn Init(display: &Display) -> Result<Self> {
let texture_bind_group_layout =
display
.device
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: true },
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler {
comparison: false,
filtering: true,
},
count: None,
},
],
label: Some("texture_bind_group_layout"),
});
// Camera
let camera = Camera {
eye: (0.0, 5.0, -10.0).into(),
target: (0.0, 0.0, 0.0).into(),
up: cgmath::Vector3::unit_y(),
aspect: display.config.width as f32 / display.config.height as f32,
fovy: 45.0,
znear: 0.1,
zfar: 100.0,
};
let camera_controller = CameraController::New(0.2);
let mut camera_uniform = CameraUniform::New();
camera_uniform.UpdateViewProjection(&camera);
let camera_buffer = display
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Camera Buffer"),
contents: bytemuck::cast_slice(&[camera_uniform]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
const SPACE_BETWEEN: f32 = 3.0;
let instances = (0..NUM_INSTANCES_PER_ROW)
.flat_map(|z| {
(0..NUM_INSTANCES_PER_ROW).map(move |x| {
let x = SPACE_BETWEEN * (x as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
let z = SPACE_BETWEEN * (z as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
let position = cgmath::Vector3 { x, y: 0.0, z };
let rotation = if position.is_zero() {
cgmath::Quaternion::from_axis_angle(
cgmath::Vector3::unit_z(),
cgmath::Deg(0.0),
)
} else {
cgmath::Quaternion::from_axis_angle(position.normalize(), cgmath::Deg(45.0))
};
Instance { position, rotation }
})
})
.collect::<Vec<_>>();
let instance_data = instances.iter().map(Instance::ToRaw).collect::<Vec<_>>();
let instance_buffer =
display
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Instance Buffer"),
contents: bytemuck::cast_slice(&instance_data),
usage: wgpu::BufferUsages::VERTEX,
});
let camera_bind_group_layout =
display
.device
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
label: Some("camera_bind_group_layout"),
});
let camera_bind_group = display
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &camera_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: camera_buffer.as_entire_binding(),
}],
label: Some("camera_bind_group"),
});
// Model
let obj_model = Model::Load(
&display.device,
&display.queue,
&texture_bind_group_layout,
PathBuf::from("./Content/SM_Cube.obj"),
)
.unwrap();
// Shader
let shader = display
.device
.create_shader_module(&wgpu::ShaderModuleDescriptor {
label: Some("shader.wgsl"),
source: wgpu::ShaderSource::Wgsl(include_str!("../Shaders/Cubes.wgsl").into()),
});
// Texture
let depth_texture =
Texture::CreateDepthTexture(&display.device, &display.config, "depth_texture");
// Pipeline
let render_pipeline_layout =
display
.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[&texture_bind_group_layout, &camera_bind_group_layout],
push_constant_ranges: &[],
});
let render_pipeline =
display
.device
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[ModelVertex::GetDescriptor(), InstanceRaw::GetDescriptor()],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[wgpu::ColorTargetState {
format: display.config.format,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent::REPLACE,
alpha: wgpu::BlendComponent::REPLACE,
}),
write_mask: wgpu::ColorWrites::ALL,
}],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
// Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
polygon_mode: wgpu::PolygonMode::Fill,
// Requires Features::DEPTH_CLAMPING
clamp_depth: false,
// Requires Features::CONSERVATIVE_RASTERIZATION
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: Texture::DEPTH_FORMAT,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
});
Ok(Self {
render_pipeline,
obj_model,
camera,
camera_controller,
camera_buffer,
camera_bind_group,
camera_uniform,
instances,
instance_buffer,
depth_texture,
})
}
fn Input(&mut self, display: &Display, event: &WindowEvent) -> bool {
self.camera_controller.ProcessEvents(event)
}
fn Update(&mut self, display: &Display, delta: Duration) {
self.camera_controller.UpdateCamera(&mut self.camera);
self.camera_uniform.UpdateViewProjection(&self.camera);
display.queue.write_buffer(
&self.camera_buffer,
0,
bytemuck::cast_slice(&[self.camera_uniform]),
);
}
fn Resize(&mut self, display: &Display) {
self.depth_texture =
Texture::CreateDepthTexture(&display.device, &display.config, "depth_texture");
}
fn Draw(&mut self, display: &mut Display) -> Result<(), wgpu::SurfaceError> {
let output = display.surface.get_current_texture().unwrap();
let view = output
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = display
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[wgpu::RenderPassColorAttachment {
view: &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::RenderPassDepthStencilAttachment {
view: &self.depth_texture.view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.0),
store: true,
}),
stencil_ops: None,
}),
});
render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..));
render_pass.set_pipeline(&self.render_pipeline);
render_pass.DrawModelInstanced(
&self.obj_model,
0..self.instances.len() as u32,
&self.camera_bind_group,
);
}
display.queue.submit(std::iter::once(encoder.finish()));
output.present();
Ok(())
}
}
fn main() -> Result<()> {
Runtime::Execute::<Cubes>()
}

View File

@ -1,177 +0,0 @@
#![allow(non_snake_case)]
#![allow(unused_variables)]
use anyhow::Result;
use bytemuck::{Pod, Zeroable};
use std::time::Duration;
use winit::event::*;
use Graphics::Render::*;
use Graphics::Shader::*;
use Graphics::{Runtime, State};
#[repr(C)]
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
struct TriangleVertex {
position: [f32; 3],
color: [f32; 3],
}
impl Vertex for TriangleVertex {
fn GetLayout() -> VertexBufferLayout {
VertexBufferLayout {
label: "Triangle".into(),
stride: std::mem::size_of::<TriangleVertex>(),
step_mode: StepMode::Vertex,
attributes: vec![
VertexAttribute {
label: "Position".into(),
format: VertexFormat::Float32x3,
offset: 0,
shader_location: 0,
},
VertexAttribute {
label: "Color".into(),
format: VertexFormat::Float32x3,
offset: std::mem::size_of::<[f32; 3]>(),
shader_location: 1,
},
],
}
}
}
#[rustfmt::skip]
const VERTICES: &[TriangleVertex] = &[
TriangleVertex { position: [0.0, 0.5, 0.0], color: [1.0, 0.0, 0.0] },
TriangleVertex { position: [-0.5, -0.5, 0.0], color: [0.0, 1.0, 0.0] },
TriangleVertex { position: [0.5, -0.5, 0.0], color: [0.0, 0.0, 1.0] },
];
#[rustfmt::skip]
const INDICES: &[u16] = &[
0, 1, 2,
];
struct Triangle {
render_pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer,
num_indices: u32,
}
impl State for Triangle {
fn Init(renderer: &Renderer) -> Result<Self> {
// Shader
let shader = Shader::FromWgsl(include_str!("../Shaders/Triangle.wgsl"));
let shader_module = renderer.SubmitShader(&shader);
// Pipeline
let render_pipeline_layout =
renderer
.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("RENDER_PIPELINE_LAYOUT"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let render_pipeline = {
let mut layout = TriangleVertex::GetLayout();
let attributes = layout
.attributes
.drain(..)
.map(|x| x.into())
.collect::<Vec<_>>();
let wgpu_layout = wgpu::VertexBufferLayout {
array_stride: layout.stride as wgpu::BufferAddress,
step_mode: layout.step_mode.into(),
attributes: attributes.as_ref(),
};
renderer
.device
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("RENDER_PIPELINE"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: &shader_module,
entry_point: "vs_main",
buffers: &[wgpu_layout],
},
fragment: Some(wgpu::FragmentState {
module: &shader_module,
entry_point: "fs_main",
targets: &[wgpu::ColorTargetState {
format: renderer.config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
}],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
})
};
let vertex_buffer = renderer.SubmitVertexBuffer(&VertexBuffer {
label: "Vertex Buffer".into(),
content: bytemuck::cast_slice(VERTICES).to_vec(),
});
let index_buffer = renderer.SubmitIndexBuffer(&IndexBuffer {
label: "Index Buffer".into(),
content: bytemuck::cast_slice(INDICES).to_vec(),
});
let num_indices = INDICES.len() as u32;
Ok(Self {
render_pipeline,
vertex_buffer,
index_buffer,
num_indices,
})
}
fn Input(&mut self, renderer: &Renderer, event: &WindowEvent) -> bool {
false
}
fn Update(&mut self, renderer: &Renderer, delta: Duration) {}
fn Resize(&mut self, renderer: &Renderer) {}
fn Draw(&mut self, renderer: &mut Renderer) -> Result<(), wgpu::SurfaceError> {
renderer
.Draw(
&self.render_pipeline,
&self.vertex_buffer,
&self.index_buffer,
self.num_indices,
)
.unwrap();
Ok(())
}
}
fn main() -> Result<()> {
Runtime::Execute::<Triangle>()
}

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 GuilhermeWerner
Copyright (c) 2024 GuilhermeWerner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1 +1 @@
# WGPU Renderer
# Renderer

View File

@ -1,58 +0,0 @@
// Vertex
struct InstanceInput {
[[location(5)]] model_matrix_0: vec4<f32>;
[[location(6)]] model_matrix_1: vec4<f32>;
[[location(7)]] model_matrix_2: vec4<f32>;
[[location(8)]] model_matrix_3: vec4<f32>;
};
[[block]]
struct CameraUniform {
view_proj: mat4x4<f32>;
};
[[group(1), binding(0)]]
var<uniform> camera: CameraUniform;
struct VertexInput {
[[location(0)]] position: vec3<f32>;
[[location(1)]] tex_coords: vec2<f32>;
};
struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>;
[[location(0)]] tex_coords: vec2<f32>;
};
[[stage(vertex)]]
fn main(
model: VertexInput,
instance: InstanceInput,
) -> VertexOutput {
let model_matrix = mat4x4<f32>(
instance.model_matrix_0,
instance.model_matrix_1,
instance.model_matrix_2,
instance.model_matrix_3,
);
var out: VertexOutput;
out.tex_coords = model.tex_coords;
out.clip_position = camera.view_proj * model_matrix * vec4<f32>(model.position, 1.0);
return out;
}
// Fragment
[[group(0), binding(0)]]
var t_diffuse: texture_2d<f32>;
[[group(0), binding(1)]]
var s_diffuse: sampler;
[[stage(fragment)]]
fn main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
}

View File

@ -1,28 +0,0 @@
// Vertex
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) color: vec3<f32>,
};
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) color: vec3<f32>,
};
@stage(vertex)
fn vs_main(
model: VertexInput,
) -> VertexOutput {
var out: VertexOutput;
out.color = model.color;
out.clip_position = vec4<f32>(model.position, 1.0);
return out;
}
// Fragment
@stage(fragment)
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(in.color, 1.0);
}

View File

@ -1,20 +0,0 @@
use super::OPENGL_TO_WGPU_MATRIX;
pub struct Camera {
pub eye: cgmath::Point3<f32>,
pub target: cgmath::Point3<f32>,
pub up: cgmath::Vector3<f32>,
pub aspect: f32,
pub fovy: f32,
pub znear: f32,
pub zfar: f32,
}
impl Camera {
pub fn BuildViewProjectionMatrix(&self) -> cgmath::Matrix4<f32> {
let view = cgmath::Matrix4::look_at_rh(self.eye, self.target, self.up);
let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar);
OPENGL_TO_WGPU_MATRIX * proj * view
}
}

View File

@ -1,105 +0,0 @@
use super::Camera;
use winit::event::*;
pub struct CameraController {
pub speed: f32,
pub is_up_pressed: bool,
pub is_down_pressed: bool,
pub is_forward_pressed: bool,
pub is_backward_pressed: bool,
pub is_left_pressed: bool,
pub is_right_pressed: bool,
}
impl CameraController {
pub fn New(speed: f32) -> Self {
Self {
speed,
is_up_pressed: false,
is_down_pressed: false,
is_forward_pressed: false,
is_backward_pressed: false,
is_left_pressed: false,
is_right_pressed: false,
}
}
pub fn ProcessEvents(&mut self, event: &WindowEvent) -> bool {
match event {
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state,
virtual_keycode: Some(keycode),
..
},
..
} => {
let is_pressed = *state == ElementState::Pressed;
match keycode {
VirtualKeyCode::Space => {
self.is_up_pressed = is_pressed;
true
}
VirtualKeyCode::LShift => {
self.is_down_pressed = is_pressed;
true
}
VirtualKeyCode::W | VirtualKeyCode::Up => {
self.is_forward_pressed = is_pressed;
true
}
VirtualKeyCode::A | VirtualKeyCode::Left => {
self.is_left_pressed = is_pressed;
true
}
VirtualKeyCode::S | VirtualKeyCode::Down => {
self.is_backward_pressed = is_pressed;
true
}
VirtualKeyCode::D | VirtualKeyCode::Right => {
self.is_right_pressed = is_pressed;
true
}
_ => false,
}
}
_ => false,
}
}
pub fn UpdateCamera(&self, camera: &mut Camera) {
use cgmath::InnerSpace;
let forward = camera.target - camera.eye;
let forward_norm = forward.normalize();
let forward_mag = forward.magnitude();
// Prevents glitching when camera gets too close to the
// center of the scene.
if self.is_forward_pressed && forward_mag > self.speed {
camera.eye += forward_norm * self.speed;
}
if self.is_backward_pressed {
camera.eye -= forward_norm * self.speed;
}
let right = forward_norm.cross(camera.up);
// Redo radius calc in case the up/ down is pressed.
let forward = camera.target - camera.eye;
let forward_mag = forward.magnitude();
if self.is_right_pressed {
// Rescale the distance between the target and eye so
// that it doesn't change. The eye therefore still
// lies on the circle made by the target and eye.
camera.eye = camera.target - (forward + right * self.speed).normalize() * forward_mag;
}
if self.is_left_pressed {
camera.eye = camera.target - (forward - right * self.speed).normalize() * forward_mag;
}
}
}

View File

@ -1,24 +0,0 @@
use super::Camera;
use bytemuck::{Pod, Zeroable};
use cgmath::SquareMatrix;
// This is so we can store this in a buffer
#[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct CameraUniform {
// We can't use cgmath with bytemuck directly so we'll have
// to convert the Matrix4 into a 4x4 f32 array
pub view_proj: [[f32; 4]; 4],
}
impl CameraUniform {
pub fn New() -> Self {
Self {
view_proj: cgmath::Matrix4::identity().into(),
}
}
pub fn UpdateViewProjection(&mut self, camera: &Camera) {
self.view_proj = camera.BuildViewProjectionMatrix().into();
}
}

View File

@ -1,20 +0,0 @@
/// Matrix to scale and translate from OpenGL coordinate system to WGPU.
#[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = 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,
);
#[path = "Camera.rs"]
mod _Camera;
pub use self::_Camera::*;
#[path = "CameraController.rs"]
mod _CameraController;
pub use self::_CameraController::*;
#[path = "CameraUniform.rs"]
mod _CameraUniform;
pub use self::_CameraUniform::*;

View File

@ -1,17 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct HslaColor {
/// Hue component. [0.0, 360.0]
pub hue: f32,
/// Saturation component. [0.0, 1.0]
pub saturation: f32,
/// Lightness component. [0.0, 1.0]
pub lightness: f32,
/// Alpha component. [0.0, 1.0]
pub alpha: f32,
}

View File

@ -1,17 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RgbaColor {
/// Red component. [0.0, 1.0]
pub red: f32,
/// Green component. [0.0, 1.0]
pub green: f32,
/// Blue component. [0.0, 1.0]
pub blue: f32,
/// Alpha component. [0.0, 1.0]
pub alpha: f32,
}

View File

@ -1,7 +0,0 @@
#[path = "HslaColor.rs"]
mod _HslaColor;
pub use self::_HslaColor::*;
#[path = "RgbaColor.rs"]
mod _RgbaColor;
pub use self::_RgbaColor::*;

View File

@ -1,66 +0,0 @@
use super::{Material, Mesh, Model};
use std::ops::Range;
pub trait DrawModel<'a> {
fn DrawMesh(
&mut self,
mesh: &'a Mesh,
material: &'a Material,
camera_bind_group: &'a wgpu::BindGroup,
);
fn DrawMeshInstanced(
&mut self,
mesh: &'a Mesh,
material: &'a Material,
instances: Range<u32>,
camera_bind_group: &'a wgpu::BindGroup,
);
fn DrawModel(&mut self, model: &'a Model, camera_bind_group: &'a wgpu::BindGroup);
fn DrawModelInstanced(
&mut self,
model: &'a Model,
instances: Range<u32>,
camera_bind_group: &'a wgpu::BindGroup,
);
}
impl<'a> DrawModel<'a> for wgpu::RenderPass<'a> {
fn DrawMesh(
&mut self,
mesh: &'a Mesh,
material: &'a Material,
camera_bind_group: &'a wgpu::BindGroup,
) {
self.DrawMeshInstanced(mesh, material, 0..1, camera_bind_group);
}
fn DrawMeshInstanced(
&mut self,
mesh: &'a Mesh,
material: &'a Material,
instances: Range<u32>,
camera_bind_group: &'a wgpu::BindGroup,
) {
self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
self.set_bind_group(0, &material.bind_group, &[]);
self.set_bind_group(1, camera_bind_group, &[]);
self.draw_indexed(0..mesh.num_elements, 0, instances);
}
fn DrawModel(&mut self, model: &'a Model, camera_bind_group: &'a wgpu::BindGroup) {
self.DrawModelInstanced(model, 0..1, camera_bind_group);
}
fn DrawModelInstanced(
&mut self,
model: &'a Model,
instances: Range<u32>,
camera_bind_group: &'a wgpu::BindGroup,
) {
for mesh in &model.meshes {
let material = &model.materials[mesh.material];
self.DrawMeshInstanced(mesh, material, instances.clone(), camera_bind_group);
}
}
}

View File

@ -1,14 +0,0 @@
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct IndexBuffer {
pub label: Cow<'static, str>,
pub content: Vec<u8>,
}
impl IndexBuffer {
pub fn GetLength(&self) -> u32 {
self.content.len() as u32
}
}

View File

@ -1,17 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum IndexFormat {
/// Indices are 16 bit unsigned integers.
UInt16 = 0,
/// Indices are 32 bit unsigned integers.
UInt32 = 1,
}
impl Default for IndexFormat {
fn default() -> Self {
Self::UInt32
}
}

View File

@ -1,71 +0,0 @@
use bytemuck::{Pod, Zeroable};
use std::mem;
pub const NUM_INSTANCES_PER_ROW: u32 = 10;
pub const NUM_INSTANCES: u32 = NUM_INSTANCES_PER_ROW * NUM_INSTANCES_PER_ROW;
pub const INSTANCE_DISPLACEMENT: cgmath::Vector3<f32> = cgmath::Vector3::new(
NUM_INSTANCES_PER_ROW as f32 * 0.5,
0.0,
NUM_INSTANCES_PER_ROW as f32 * 0.5,
);
pub struct Instance {
pub position: cgmath::Vector3<f32>,
pub rotation: cgmath::Quaternion<f32>,
}
impl Instance {
pub fn ToRaw(&self) -> InstanceRaw {
InstanceRaw {
model: (cgmath::Matrix4::from_translation(self.position)
* cgmath::Matrix4::from(self.rotation))
.into(),
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct InstanceRaw {
pub model: [[f32; 4]; 4],
}
impl InstanceRaw {
pub fn GetDescriptor<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: mem::size_of::<InstanceRaw>() as wgpu::BufferAddress,
// We need to switch from using a step mode of Vertex to Instance
// This means that our shaders will only change to use the next
// instance when the shader starts processing a new instance
step_mode: wgpu::VertexStepMode::Instance,
attributes: &[
wgpu::VertexAttribute {
offset: 0,
// While our vertex shader only uses locations 0, and 1 now, in later tutorials we'll
// be using 2, 3, and 4, for Vertex. We'll start at slot 5 not conflict with them later
shader_location: 5,
format: wgpu::VertexFormat::Float32x4,
},
// A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot
// for each vec4. We'll have to reassemble the mat4 in
// the shader.
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
shader_location: 6,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
shader_location: 7,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
shader_location: 8,
format: wgpu::VertexFormat::Float32x4,
},
],
}
}
}

View File

@ -1,7 +0,0 @@
use super::Texture;
pub struct Material {
pub name: String,
pub diffuse_texture: Texture,
pub bind_group: wgpu::BindGroup,
}

View File

@ -1,7 +0,0 @@
pub struct Mesh {
pub name: String,
pub vertex_buffer: wgpu::Buffer,
pub index_buffer: wgpu::Buffer,
pub num_elements: u32,
pub material: usize,
}

View File

@ -1,139 +0,0 @@
use super::Texture;
use super::{Material, Mesh, Vertex};
use anyhow::Result;
use bytemuck::{Pod, Zeroable};
use std::path::Path;
use tobj::LoadOptions;
use wgpu::util::DeviceExt;
pub struct Model {
pub meshes: Vec<Mesh>,
pub materials: Vec<Material>,
}
impl Model {
pub fn Load<P: AsRef<Path>>(
device: &wgpu::Device,
queue: &wgpu::Queue,
layout: &wgpu::BindGroupLayout,
path: P,
) -> Result<Self> {
let (obj_models, obj_materials) = tobj::load_obj(
path.as_ref(),
&LoadOptions {
triangulate: true,
single_index: true,
..Default::default()
},
)?;
let obj_materials = obj_materials?;
// We're assuming that the texture files are stored with the obj file
let containing_folder = path.as_ref().parent().expect("Directory has no parent");
let mut materials = Vec::new();
for mat in obj_materials {
let diffuse_path = mat.diffuse_texture;
let diffuse_texture =
Texture::Load(device, queue, containing_folder.join(diffuse_path))?;
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
},
],
label: None,
});
materials.push(Material {
name: mat.name,
diffuse_texture,
bind_group,
});
}
let mut meshes = Vec::new();
for m in obj_models {
let mut vertices = Vec::new();
for i in 0..m.mesh.positions.len() / 3 {
vertices.push(ModelVertex {
position: [
m.mesh.positions[i * 3],
m.mesh.positions[i * 3 + 1],
m.mesh.positions[i * 3 + 2],
],
tex_coords: [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]],
normal: [
m.mesh.normals[i * 3],
m.mesh.normals[i * 3 + 1],
m.mesh.normals[i * 3 + 2],
],
});
}
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", path.as_ref())),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Index Buffer", path.as_ref())),
contents: bytemuck::cast_slice(&m.mesh.indices),
usage: wgpu::BufferUsages::INDEX,
});
meshes.push(Mesh {
name: m.name,
vertex_buffer,
index_buffer,
num_elements: m.mesh.indices.len() as u32,
material: m.mesh.material_id.unwrap_or(0),
});
}
Ok(Self { meshes, materials })
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
pub struct ModelVertex {
position: [f32; 3],
tex_coords: [f32; 2],
normal: [f32; 3],
}
impl Vertex for ModelVertex {
fn GetDescriptor<'a>() -> wgpu::VertexBufferLayout<'a> {
use std::mem;
wgpu::VertexBufferLayout {
array_stride: mem::size_of::<ModelVertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
shader_location: 1,
format: wgpu::VertexFormat::Float32x2,
},
wgpu::VertexAttribute {
offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress,
shader_location: 2,
format: wgpu::VertexFormat::Float32x3,
},
],
}
}
}

View File

@ -1,20 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum PolygonMode {
/// Polygons are filled
Fill = 0,
/// Polygons are drawn as line segments
Line = 1,
/// Polygons are drawn as points
Point = 2,
}
impl Default for PolygonMode {
fn default() -> Self {
Self::Fill
}
}

View File

@ -1,154 +0,0 @@
use super::{IndexBuffer, UniformBuffer, VertexBuffer};
use crate::Shader::Shader;
use anyhow::Result;
use wgpu::util::DeviceExt;
use winit::window::Window;
pub struct Renderer {
pub surface: wgpu::Surface,
pub window: Window,
pub config: wgpu::SurfaceConfiguration,
pub device: wgpu::Device,
pub queue: wgpu::Queue,
}
impl Renderer {
pub async fn New(window: Window) -> Result<Self> {
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::Backends::DX12);
let surface = unsafe { instance.create_surface(&window) };
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
})
.await
.unwrap();
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
},
None,
)
.await
.unwrap();
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: surface.get_preferred_format(&adapter).unwrap(),
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Fifo,
};
surface.configure(&device, &config);
Ok(Self {
surface,
window,
config,
device,
queue,
})
}
pub fn SubmitShader(&self, shader: &Shader) -> wgpu::ShaderModule {
let src = shader.source.WgslToString().unwrap();
self.device
.create_shader_module(&wgpu::ShaderModuleDescriptor {
label: Some(&shader.label),
source: wgpu::ShaderSource::Wgsl(src.as_str().into()),
})
}
pub fn SubmitVertexBuffer(&self, vertex_buffer: &VertexBuffer) -> wgpu::Buffer {
self.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&vertex_buffer.label),
contents: vertex_buffer.content.as_ref(),
usage: wgpu::BufferUsages::VERTEX,
})
}
pub fn SubmitIndexBuffer(&self, index_buffer: &IndexBuffer) -> wgpu::Buffer {
self.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&index_buffer.label),
contents: index_buffer.content.as_ref(),
usage: wgpu::BufferUsages::INDEX,
})
}
pub fn SubmitUniformBuffer(&self, uniform_buffer: &UniformBuffer) -> wgpu::Buffer {
self.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&uniform_buffer.label),
contents: uniform_buffer.content.as_ref(),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
})
}
pub fn Draw(
&self,
pipeline: &wgpu::RenderPipeline,
vertex_buffer: &wgpu::Buffer,
index_buffer: &wgpu::Buffer,
num_indices: u32,
) -> Result<()> {
let output = self.surface.get_current_texture()?;
let view = output
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("RENDER_ENCODER"),
});
{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("RENDER_PASS"),
color_attachments: &[wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
}),
store: true,
},
}],
depth_stencil_attachment: None,
});
render_pass.set_pipeline(pipeline);
render_pass.set_vertex_buffer(0, vertex_buffer.slice(..));
render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint16);
render_pass.draw_indexed(0..num_indices, 0, 0..1);
}
self.queue.submit(std::iter::once(encoder.finish()));
output.present();
Ok(())
}
pub fn Resize(&mut self, width: u32, height: u32) {
self.config.width = width;
self.config.height = height;
self.surface.configure(&self.device, &self.config);
}
}

View File

@ -1,23 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum StepMode {
Vertex = 0,
Instance = 1,
}
impl Default for StepMode {
fn default() -> Self {
StepMode::Vertex
}
}
impl From<StepMode> for wgpu::VertexStepMode {
fn from(step_mode: StepMode) -> Self {
match step_mode {
StepMode::Vertex => wgpu::VertexStepMode::Vertex,
StepMode::Instance => wgpu::VertexStepMode::Instance,
}
}
}

View File

@ -1,156 +0,0 @@
use anyhow::*;
use image::GenericImageView;
use std::path::Path;
/// Texture coordinates.
///
/// ```no_run
/// (0.0) (1.0)
/// V1 ----------------- V2
/// | / |
/// | Q1 / |
/// | / |
/// | / |
/// | / |
/// | / Q2 |
/// | / |
/// V3 ----------------- V4
/// (0.1) (1.1)
/// ```
pub struct Texture {
pub texture: wgpu::Texture,
pub view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
}
impl Texture {
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
pub fn Load<P: AsRef<Path>>(
device: &wgpu::Device,
queue: &wgpu::Queue,
path: P,
) -> Result<Self> {
// Needed to appease the borrow checker
let path_copy = path.as_ref().to_path_buf();
let label = path_copy.to_str();
let img = image::open(path)?;
Self::FromImage(device, queue, &img, label)
}
pub fn FromBytes(
device: &wgpu::Device,
queue: &wgpu::Queue,
bytes: &[u8],
label: &str,
) -> Result<Self> {
let img = image::load_from_memory(bytes)?;
Self::FromImage(device, queue, &img, Some(label))
}
pub fn FromImage(
device: &wgpu::Device,
queue: &wgpu::Queue,
img: &image::DynamicImage,
label: Option<&str>,
) -> Result<Self> {
let rgba = img.to_rgba8();
let dimensions = img.dimensions();
let size = wgpu::Extent3d {
width: dimensions.0,
height: dimensions.1,
depth_or_array_layers: 1,
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label,
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
});
queue.write_texture(
wgpu::ImageCopyTexture {
aspect: wgpu::TextureAspect::All,
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
},
&rgba,
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: std::num::NonZeroU32::new(4 * dimensions.0),
rows_per_image: std::num::NonZeroU32::new(dimensions.1),
},
size,
);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
Ok(Self {
texture,
view,
sampler,
})
}
pub fn CreateDepthTexture(
device: &wgpu::Device,
config: &wgpu::SurfaceConfiguration,
label: &str,
) -> Self {
let size = wgpu::Extent3d {
width: config.width,
height: config.height,
depth_or_array_layers: 1,
};
let desc = wgpu::TextureDescriptor {
label: Some(label),
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: Self::DEPTH_FORMAT,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
};
let texture = device.create_texture(&desc);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
compare: Some(wgpu::CompareFunction::LessEqual),
lod_min_clamp: -100.0,
lod_max_clamp: 100.0,
..Default::default()
});
Self {
texture,
view,
sampler,
}
}
}

View File

@ -1,8 +0,0 @@
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct UniformBuffer {
pub label: Cow<'static, str>,
pub content: Vec<u8>,
}

View File

@ -1,5 +0,0 @@
use super::VertexBufferLayout;
pub trait Vertex {
fn GetLayout() -> VertexBufferLayout;
}

View File

@ -1,21 +0,0 @@
use super::VertexFormat;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct VertexAttribute {
pub label: Cow<'static, str>,
pub format: VertexFormat,
pub offset: usize,
pub shader_location: u32,
}
impl From<VertexAttribute> for wgpu::VertexAttribute {
fn from(attr: VertexAttribute) -> Self {
wgpu::VertexAttribute {
offset: attr.offset as wgpu::BufferAddress,
shader_location: attr.shader_location,
format: attr.format.into(),
}
}
}

View File

@ -1,8 +0,0 @@
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct VertexBuffer {
pub label: Cow<'static, str>,
pub content: Vec<u8>,
}

View File

@ -1,11 +0,0 @@
use super::{StepMode, VertexAttribute};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct VertexBufferLayout {
pub label: Cow<'static, str>,
pub stride: usize,
pub step_mode: StepMode,
pub attributes: Vec<VertexAttribute>,
}

View File

@ -1,190 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum VertexFormat {
/// Two unsigned bytes (u8). `uvec2` in shaders.
UInt8x2 = 0,
/// Four unsigned bytes (u8). `uvec4` in shaders.
UInt8x4 = 1,
/// Two signed bytes (i8). `ivec2` in shaders.
Int8x2 = 2,
/// Four signed bytes (i8). `ivec4` in shaders.
Int8x4 = 3,
/// Two unsigned bytes (u8). [0, 255] converted to float [0, 1] `vec2` in shaders.
UNorm8x2 = 4,
/// Four unsigned bytes (u8). [0, 255] converted to float [0, 1] `vec4` in shaders.
UNorm8x4 = 5,
/// Two signed bytes (i8). [-127, 127] converted to float [-1, 1] `vec2` in shaders.
Norm8x2 = 6,
/// Four signed bytes (i8). [-127, 127] converted to float [-1, 1] `vec4` in shaders.
Norm8x4 = 7,
/// Two unsigned shorts (u16). `uvec2` in shaders.
UInt16x2 = 8,
/// Four unsigned shorts (u16). `uvec4` in shaders.
UInt16x4 = 9,
/// Two signed shorts (i16). `ivec2` in shaders.
Int16x2 = 10,
/// Four signed shorts (i16). `ivec4` in shaders.
Int16x4 = 11,
/// Two unsigned shorts (u16). [0, 65535] converted to float [0, 1] `vec2` in shaders.
UNorm16x2 = 12,
/// Four unsigned shorts (u16). [0, 65535] converted to float [0, 1] `vec4` in shaders.
UNorm16x4 = 13,
/// Two signed shorts (i16). [-32767, 32767] converted to float [-1, 1] `vec2` in shaders.
Norm16x2 = 14,
/// Four signed shorts (i16). [-32767, 32767] converted to float [-1, 1] `vec4` in shaders.
Norm16x4 = 15,
/// Two half-precision floats (no Rust equiv). `vec2` in shaders.
Float16x2 = 16,
/// Four half-precision floats (no Rust equiv). `vec4` in shaders.
Float16x4 = 17,
/// One single-precision float (f32). `float` in shaders.
Float32 = 18,
/// Two single-precision floats (f32). `vec2` in shaders.
Float32x2 = 19,
/// Three single-precision floats (f32). `vec3` in shaders.
Float32x3 = 20,
/// Four single-precision floats (f32). `vec4` in shaders.
Float32x4 = 21,
/// One unsigned int (u32). `uint` in shaders.
UInt32 = 22,
/// Two unsigned ints (u32). `uvec2` in shaders.
UInt32x2 = 23,
/// Three unsigned ints (u32). `uvec3` in shaders.
UInt32x3 = 24,
/// Four unsigned ints (u32). `uvec4` in shaders.
UInt32x4 = 25,
/// One signed int (i32). `int` in shaders.
Int32 = 26,
/// Two signed ints (i32). `ivec2` in shaders.
Int32x2 = 27,
/// Three signed ints (i32). `ivec3` in shaders.
Int32x3 = 28,
/// Four signed ints (i32). `ivec4` in shaders.
Int32x4 = 29,
/// One double-precision float (f64). `double` in shaders.
Float64 = 30,
/// Two double-precision floats (f64). `dvec2` in shaders.
Float64x2 = 31,
/// Three double-precision floats (f64). `dvec3` in shaders.
Float64x3 = 32,
/// Four double-precision floats (f64). `dvec4` in shaders.
Float64x4 = 33,
}
impl VertexFormat {
/// Returns the size in bytes of this format.
pub const fn GetSize(&self) -> u64 {
match *self {
Self::UInt8x2 => 2,
Self::UInt8x4 => 4,
Self::Int8x2 => 2,
Self::Int8x4 => 4,
Self::UNorm8x2 => 2,
Self::UNorm8x4 => 4,
Self::Norm8x2 => 2,
Self::Norm8x4 => 4,
Self::UInt16x2 => 2 * 2,
Self::UInt16x4 => 4 * 4,
Self::Int16x2 => 2 * 2,
Self::Int16x4 => 2 * 4,
Self::UNorm16x2 => 2 * 2,
Self::UNorm16x4 => 2 * 4,
Self::Norm16x2 => 2 * 2,
Self::Norm16x4 => 2 * 4,
Self::Float16x2 => 2 * 2,
Self::Float16x4 => 2 * 4,
Self::Float32 => 4,
Self::Float32x2 => 4 * 2,
Self::Float32x3 => 4 * 3,
Self::Float32x4 => 4 * 4,
Self::UInt32 => 4,
Self::UInt32x2 => 4 * 2,
Self::UInt32x3 => 4 * 3,
Self::UInt32x4 => 4 * 4,
Self::Int32 => 4,
Self::Int32x2 => 4 * 2,
Self::Int32x3 => 4 * 3,
Self::Int32x4 => 4 * 4,
Self::Float64 => 8,
Self::Float64x2 => 8 * 2,
Self::Float64x3 => 8 * 3,
Self::Float64x4 => 8 * 4,
}
}
}
impl From<VertexFormat> for wgpu::VertexFormat {
fn from(format: VertexFormat) -> Self {
match format {
VertexFormat::UInt8x2 => wgpu::VertexFormat::Uint8x2,
VertexFormat::UInt8x4 => wgpu::VertexFormat::Uint8x4,
VertexFormat::Int8x2 => wgpu::VertexFormat::Sint8x2,
VertexFormat::Int8x4 => wgpu::VertexFormat::Sint8x4,
VertexFormat::UNorm8x2 => wgpu::VertexFormat::Unorm8x2,
VertexFormat::UNorm8x4 => wgpu::VertexFormat::Unorm8x4,
VertexFormat::Norm8x2 => wgpu::VertexFormat::Snorm8x2,
VertexFormat::Norm8x4 => wgpu::VertexFormat::Snorm8x4,
VertexFormat::UInt16x2 => wgpu::VertexFormat::Uint16x2,
VertexFormat::UInt16x4 => wgpu::VertexFormat::Uint16x4,
VertexFormat::Int16x2 => wgpu::VertexFormat::Sint16x2,
VertexFormat::Int16x4 => wgpu::VertexFormat::Sint16x4,
VertexFormat::UNorm16x2 => wgpu::VertexFormat::Unorm16x2,
VertexFormat::UNorm16x4 => wgpu::VertexFormat::Unorm16x4,
VertexFormat::Norm16x2 => wgpu::VertexFormat::Snorm16x2,
VertexFormat::Norm16x4 => wgpu::VertexFormat::Snorm16x4,
VertexFormat::Float16x2 => wgpu::VertexFormat::Float16x2,
VertexFormat::Float16x4 => wgpu::VertexFormat::Float16x4,
VertexFormat::Float32 => wgpu::VertexFormat::Float32,
VertexFormat::Float32x2 => wgpu::VertexFormat::Float32x2,
VertexFormat::Float32x3 => wgpu::VertexFormat::Float32x3,
VertexFormat::Float32x4 => wgpu::VertexFormat::Float32x4,
VertexFormat::UInt32 => wgpu::VertexFormat::Uint32,
VertexFormat::UInt32x2 => wgpu::VertexFormat::Uint32x2,
VertexFormat::UInt32x3 => wgpu::VertexFormat::Uint32x3,
VertexFormat::UInt32x4 => wgpu::VertexFormat::Uint32x4,
VertexFormat::Int32 => wgpu::VertexFormat::Sint32,
VertexFormat::Int32x2 => wgpu::VertexFormat::Sint32x2,
VertexFormat::Int32x3 => wgpu::VertexFormat::Sint32x3,
VertexFormat::Int32x4 => wgpu::VertexFormat::Sint32x4,
VertexFormat::Float64 => wgpu::VertexFormat::Float64,
VertexFormat::Float64x2 => wgpu::VertexFormat::Float64x2,
VertexFormat::Float64x3 => wgpu::VertexFormat::Float64x3,
VertexFormat::Float64x4 => wgpu::VertexFormat::Float64x4,
}
}
}

View File

@ -1,67 +0,0 @@
//#[path = "DrawModel.rs"]
//mod _DrawModel;
//pub use self::_DrawModel::*;
#[path = "IndexFormat.rs"]
mod _IndexFormat;
pub use self::_IndexFormat::*;
//#[path = "Instance.rs"]
//mod _Instance;
//pub use self::_Instance::*;
//#[path = "Material.rs"]
//mod _Material;
//pub use self::_Material::*;
//#[path = "Model.rs"]
//mod _Model;
//pub use self::_Model::*;
#[path = "PolygonMode.rs"]
mod _PolygonMode;
pub use self::_PolygonMode::*;
#[path = "Renderer.rs"]
mod _Renderer;
pub use self::_Renderer::*;
#[path = "StepMode.rs"]
mod _StepMode;
pub use self::_StepMode::*;
//#[path = "Mesh.rs"]
//mod _Mesh;
//pub use self::_Mesh::*;
//#[path = "Texture.rs"]
//mod _Texture;
//pub use self::_Texture::*;
#[path = "Vertex.rs"]
mod _Vertex;
pub use self::_Vertex::*;
#[path = "VertexAttribute.rs"]
mod _VertexAttribute;
pub use self::_VertexAttribute::*;
#[path = "VertexBufferLayout.rs"]
mod _VertexBufferLayout;
pub use self::_VertexBufferLayout::*;
#[path = "VertexFormat.rs"]
mod _VertexFormat;
pub use self::_VertexFormat::*;
#[path = "VertexBuffer.rs"]
mod _VertexBuffer;
pub use self::_VertexBuffer::*;
#[path = "IndexBuffer.rs"]
mod _IndexBuffer;
pub use self::_IndexBuffer::*;
#[path = "UniformBuffer.rs"]
mod _UniformBuffer;
pub use self::_UniformBuffer::*;

View File

@ -1,114 +0,0 @@
use crate::Render::Renderer;
use crate::State;
use anyhow::Result;
use std::time::Instant;
use winit::dpi::LogicalSize;
use winit::event::*;
use winit::event_loop::{ControlFlow, EventLoop};
use winit::monitor::{MonitorHandle, VideoMode};
use winit::window::{Fullscreen, WindowBuilder};
/// Runtime state executor and event loop.
pub struct Runtime;
impl Runtime {
pub fn Execute<T: State>() -> Result<()> {
env_logger::init();
let event_loop = EventLoop::new();
//let monitor = event_loop.available_monitors().nth(0);
let window = WindowBuilder::new()
.with_title("Graphics")
//.with_fullscreen(Some(Fullscreen::Borderless(monitor)))
.with_inner_size(LogicalSize::new(1280, 720))
.build(&event_loop)?;
let mut renderer = pollster::block_on(Renderer::New(window))?;
let mut app = T::Init(&renderer)?;
let mut last_update = Instant::now();
let mut is_resumed = true;
let mut is_focused = true;
let mut is_redraw_requested = true;
event_loop.run(move |event, _, control_flow| {
*control_flow = if is_resumed && is_focused {
ControlFlow::Poll
} else {
ControlFlow::Wait
};
match event {
Event::Resumed => is_resumed = true,
Event::Suspended => is_resumed = false,
Event::RedrawRequested(window_id) => {
if window_id == renderer.window.id() {
let now = Instant::now();
let delta = now - last_update;
last_update = now;
app.Update(&renderer, delta);
match app.Draw(&mut renderer) {
Ok(_) => {}
// Reconfigure the surface if lost
Err(wgpu::SurfaceError::Lost) => {
let size = renderer.window.inner_size();
renderer.Resize(size.width, size.height);
app.Resize(&renderer);
}
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
*control_flow = ControlFlow::Exit
}
// All other errors (Outdated, Timeout) should be resolved by the next frame
Err(e) => eprintln!("{:?}", e),
}
is_redraw_requested = false;
}
}
Event::MainEventsCleared => {
if is_focused && is_resumed && !is_redraw_requested {
renderer.window.request_redraw();
is_redraw_requested = true;
} else {
// Freeze time while the app is not in the foreground
last_update = Instant::now();
}
}
Event::WindowEvent { event, window_id } if window_id == renderer.window.id() => {
if !app.Input(&renderer, &event) {
match event {
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
..
} => *control_flow = ControlFlow::Exit,
WindowEvent::Focused(focused) => is_focused = focused,
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
renderer.Resize(new_inner_size.width, new_inner_size.height);
app.Resize(&renderer);
}
WindowEvent::Resized(physical_size) => {
renderer.Resize(physical_size.width, physical_size.height);
app.Resize(&renderer);
}
_ => {}
}
}
}
_ => {}
}
})
}
}

View File

@ -1,46 +0,0 @@
use super::{ShaderSource, ShaderStage};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct Shader {
pub label: Cow<'static, str>,
pub source: ShaderSource,
pub stage: ShaderStage,
}
impl Shader {
pub fn New(stage: ShaderStage, source: ShaderSource) -> Self {
Self {
label: "".into(),
source,
stage,
}
}
/*
pub fn FromSpirv(spirv: &[u8]) -> Self {
Self {
label: "".into(),
source: ShaderSource::Spirv(spirv),
stage,
}
}
*/
pub fn FromGlsl(stage: ShaderStage, glsl: &str) -> Self {
Self {
label: "".into(),
source: ShaderSource::Glsl(glsl.to_string()),
stage,
}
}
pub fn FromWgsl(wgsl: &str) -> Self {
Self {
label: "".into(),
source: ShaderSource::Wgsl(wgsl.to_string()),
stage: ShaderStage::Multiple,
}
}
}

View File

@ -1,22 +0,0 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ShaderSource {
Glsl(String),
Spirv(Vec<u8>),
Wgsl(String),
}
impl ShaderSource {
pub fn SpirvFromBytes(bytes: &[u8]) -> ShaderSource {
ShaderSource::Spirv(Vec::from(bytes))
}
pub fn WgslToString(&self) -> Option<&String> {
if let ShaderSource::Wgsl(s) = &self {
Some(s)
} else {
None
}
}
}

View File

@ -1,17 +0,0 @@
use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub enum ShaderStage {
/// Handles the processing of individual vertices
Vertex = 0,
/// Process a fragment generated by the rasterization into a set of colors and a single depth value.
Fragment = 1,
/// Used entirely for computing arbitrary information
Compute = 2,
/// Multi-stage shader, used with wgsl sources.
Multiple = 3,
}

View File

@ -1,11 +0,0 @@
#[path = "Shader.rs"]
mod _Shader;
pub use self::_Shader::*;
#[path = "ShaderSource.rs"]
mod _ShaderSource;
pub use self::_ShaderSource::*;
#[path = "ShaderStage.rs"]
mod _ShaderStage;
pub use self::_ShaderStage::*;

View File

@ -1,13 +0,0 @@
use crate::Render::Renderer;
use anyhow::Result;
use std::time::Duration;
use winit::event::*;
/// Represents a application with reactive state.
pub trait State: Sized + 'static {
fn Init(renderer: &Renderer) -> Result<Self>;
fn Input(&mut self, renderer: &Renderer, event: &WindowEvent) -> bool;
fn Update(&mut self, renderer: &Renderer, delta: Duration);
fn Resize(&mut self, renderer: &Renderer);
fn Draw(&mut self, renderer: &mut Renderer) -> Result<(), wgpu::SurfaceError>;
}

View File

@ -1,15 +0,0 @@
#![allow(non_snake_case)]
#![allow(unused_imports)]
pub mod Camera;
pub mod Color;
pub mod Render;
pub mod Shader;
#[path = "Runtime.rs"]
mod _Runtime;
pub use self::_Runtime::*;
#[path = "State.rs"]
mod _State;
pub use self::_State::*;

0
src/lib.rs Normal file
View File

1
src/main.rs Normal file
View File

@ -0,0 +1 @@
fn main() {}