mirror of
https://github.com/hannobraun/Fornjot
synced 2025-10-14 11:58:20 +00:00
Merge pull request #1573 from erenoku/navigation_cube
Add navigation cube
This commit is contained in:
commit
5879a0c650
40
Cargo.lock
generated
40
Cargo.lock
generated
@ -51,6 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
@ -581,6 +582,12 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color_quant"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@ -1267,9 +1274,12 @@ dependencies = [
|
|||||||
"fj-interop",
|
"fj-interop",
|
||||||
"fj-math",
|
"fj-math",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
|
"image",
|
||||||
|
"nalgebra",
|
||||||
"raw-window-handle 0.5.0",
|
"raw-window-handle 0.5.0",
|
||||||
"rfd",
|
"rfd",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"tobj",
|
||||||
"tracing",
|
"tracing",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"wgpu_glyph",
|
"wgpu_glyph",
|
||||||
@ -1807,6 +1817,21 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image"
|
||||||
|
version = "0.24.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"byteorder 1.4.3",
|
||||||
|
"color_quant",
|
||||||
|
"jpeg-decoder",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
"png",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.2"
|
version = "1.9.2"
|
||||||
@ -1910,6 +1935,12 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jpeg-decoder"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.61"
|
version = "0.3.61"
|
||||||
@ -3737,6 +3768,15 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tobj"
|
||||||
|
version = "3.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d0bde887a49e2e09f30ba3b454cdba3fbc971703e436c527f9f69a035b45b9b"
|
||||||
|
dependencies = [
|
||||||
|
"ahash 0.8.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.25.0"
|
version = "1.25.0"
|
||||||
|
BIN
assets/navigation_cube/bottom.png
Normal file
BIN
assets/navigation_cube/bottom.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
assets/navigation_cube/cube.blend
Normal file
BIN
assets/navigation_cube/cube.blend
Normal file
Binary file not shown.
62
assets/navigation_cube/cube.mtl
Normal file
62
assets/navigation_cube/cube.mtl
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Blender 3.4.1 MTL File: 'cube.blend'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl bottom
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd bottom.png
|
||||||
|
|
||||||
|
newmtl front
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd front.png
|
||||||
|
|
||||||
|
newmtl left
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd left.png
|
||||||
|
|
||||||
|
newmtl rear
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd rear.png
|
||||||
|
|
||||||
|
newmtl right
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd right.png
|
||||||
|
|
||||||
|
newmtl top
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd top.png
|
51
assets/navigation_cube/cube.obj
Normal file
51
assets/navigation_cube/cube.obj
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Blender 3.4.1
|
||||||
|
# www.blender.org
|
||||||
|
mtllib 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
|
||||||
|
vn -0.0000 1.0000 -0.0000
|
||||||
|
vn -1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 -1.0000
|
||||||
|
vn -0.0000 -1.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 1.0000
|
||||||
|
vn 1.0000 -0.0000 -0.0000
|
||||||
|
vt 0.999900 0.000100
|
||||||
|
vt 0.999900 0.999900
|
||||||
|
vt 0.000100 0.999900
|
||||||
|
vt 0.999900 0.999900
|
||||||
|
vt 0.999900 0.000100
|
||||||
|
vt 0.000100 0.000100
|
||||||
|
vt 0.000100 0.000100
|
||||||
|
vt 0.999900 0.999900
|
||||||
|
vt 0.000100 0.999900
|
||||||
|
vt 0.999900 0.000100
|
||||||
|
vt 0.000100 0.999900
|
||||||
|
vt 0.000100 0.000100
|
||||||
|
vt 0.000100 0.999900
|
||||||
|
vt 0.999900 0.999900
|
||||||
|
vt 0.000100 0.000100
|
||||||
|
vt 0.999900 0.000100
|
||||||
|
vt 0.000100 0.999900
|
||||||
|
vt 0.999900 0.999900
|
||||||
|
vt 0.999900 0.000100
|
||||||
|
vt 0.000100 0.000100
|
||||||
|
s 0
|
||||||
|
usemtl top
|
||||||
|
f 1/1/1 5/14/1 7/17/1 3/7/1
|
||||||
|
usemtl left
|
||||||
|
f 4/10/2 3/8/2 7/17/2 8/20/2
|
||||||
|
usemtl front
|
||||||
|
f 2/5/5 1/2/5 3/9/5 4/12/5
|
||||||
|
usemtl right
|
||||||
|
f 6/16/6 5/14/6 1/3/6 2/6/6
|
||||||
|
usemtl rear
|
||||||
|
f 8/19/3 7/18/3 5/13/3 6/15/3
|
||||||
|
usemtl bottom
|
||||||
|
f 6/16/4 2/4/4 4/11/4 8/20/4
|
BIN
assets/navigation_cube/front.png
Normal file
BIN
assets/navigation_cube/front.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
assets/navigation_cube/left.png
Normal file
BIN
assets/navigation_cube/left.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
assets/navigation_cube/rear.png
Normal file
BIN
assets/navigation_cube/rear.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
assets/navigation_cube/right.png
Normal file
BIN
assets/navigation_cube/right.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
assets/navigation_cube/top.png
Normal file
BIN
assets/navigation_cube/top.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -40,6 +40,13 @@ impl Transform {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Construct a scaling
|
||||||
|
pub fn scale(scaling_factor: f64) -> Self {
|
||||||
|
Self(nalgebra::Transform::from_matrix_unchecked(
|
||||||
|
nalgebra::OMatrix::new_scaling(scaling_factor),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Transform the given point
|
/// Transform the given point
|
||||||
pub fn transform_point(&self, point: &Point<3>) -> Point<3> {
|
pub fn transform_point(&self, point: &Point<3>) -> Point<3> {
|
||||||
Point::from(self.0.transform_point(&point.to_na()))
|
Point::from(self.0.transform_point(&point.to_na()))
|
||||||
@ -119,6 +126,11 @@ impl Transform {
|
|||||||
array.map(Scalar::from)
|
array.map(Scalar::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a copy of the inner nalgebra transform
|
||||||
|
pub fn get_inner(&self) -> nalgebra::Transform<f64, nalgebra::TAffine, 3> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Transform the given axis-aligned bounding box
|
/// Transform the given axis-aligned bounding box
|
||||||
pub fn transform_aabb(&self, aabb: &Aabb<3>) -> Aabb<3> {
|
pub fn transform_aabb(&self, aabb: &Aabb<3>) -> Aabb<3> {
|
||||||
Aabb {
|
Aabb {
|
||||||
|
@ -18,11 +18,18 @@ egui = "0.20.1"
|
|||||||
egui-wgpu = "0.20.0"
|
egui-wgpu = "0.20.0"
|
||||||
fj-interop.workspace = true
|
fj-interop.workspace = true
|
||||||
fj-math.workspace = true
|
fj-math.workspace = true
|
||||||
|
nalgebra = "0.32.1"
|
||||||
|
tobj = "3.2.4"
|
||||||
raw-window-handle = "0.5.0"
|
raw-window-handle = "0.5.0"
|
||||||
thiserror = "1.0.35"
|
thiserror = "1.0.35"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
wgpu_glyph = "0.18.0"
|
wgpu_glyph = "0.18.0"
|
||||||
|
|
||||||
|
[dependencies.image]
|
||||||
|
version = "0.24"
|
||||||
|
default-features = false
|
||||||
|
features = ["png", "jpeg"]
|
||||||
|
|
||||||
[dependencies.rfd]
|
[dependencies.rfd]
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
default_features = false
|
default_features = false
|
||||||
|
59
crates/fj-viewer/src/assets.rs
Normal file
59
crates/fj-viewer/src/assets.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
pub struct Assets<'a> {
|
||||||
|
pub cube_obj: &'a [u8],
|
||||||
|
pub cube_mtl: &'a [u8],
|
||||||
|
pub front_texture: &'a [u8],
|
||||||
|
pub right_texture: &'a [u8],
|
||||||
|
pub rear_texture: &'a [u8],
|
||||||
|
pub left_texture: &'a [u8],
|
||||||
|
pub top_texture: &'a [u8],
|
||||||
|
pub bottom_texture: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Assets<'a> {
|
||||||
|
pub fn get_instance() -> Self {
|
||||||
|
let cube_obj: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/cube.obj");
|
||||||
|
let cube_mtl: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/cube.mtl");
|
||||||
|
let front_texture: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/front.png");
|
||||||
|
let right_texture: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/right.png");
|
||||||
|
let rear_texture: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/rear.png");
|
||||||
|
let left_texture: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/left.png");
|
||||||
|
let top_texture: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/top.png");
|
||||||
|
let bottom_texture: &[u8] =
|
||||||
|
include_bytes!("../../../assets/navigation_cube/bottom.png");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cube_obj,
|
||||||
|
cube_mtl,
|
||||||
|
front_texture,
|
||||||
|
right_texture,
|
||||||
|
rear_texture,
|
||||||
|
left_texture,
|
||||||
|
top_texture,
|
||||||
|
bottom_texture,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_asset(&self, file_name: &str) -> &[u8] {
|
||||||
|
match file_name {
|
||||||
|
"cube.obj" => self.cube_obj,
|
||||||
|
"cube.mtl" => self.cube_mtl,
|
||||||
|
"front.png" => self.front_texture,
|
||||||
|
"right.png" => self.right_texture,
|
||||||
|
"rear.png" => self.rear_texture,
|
||||||
|
"left.png" => self.left_texture,
|
||||||
|
"top.png" => self.top_texture,
|
||||||
|
"bottom.png" => self.bottom_texture,
|
||||||
|
_ => unreachable!(
|
||||||
|
"An unknown asset: {} is trying to be loaded",
|
||||||
|
file_name
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,12 @@
|
|||||||
mod draw_config;
|
mod draw_config;
|
||||||
mod drawables;
|
mod drawables;
|
||||||
mod geometries;
|
mod geometries;
|
||||||
|
mod model;
|
||||||
|
mod navigation_cube;
|
||||||
mod pipelines;
|
mod pipelines;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
mod shaders;
|
mod shaders;
|
||||||
|
mod texture;
|
||||||
mod transform;
|
mod transform;
|
||||||
mod uniforms;
|
mod uniforms;
|
||||||
mod vertices;
|
mod vertices;
|
||||||
|
226
crates/fj-viewer/src/graphics/model.rs
Normal file
226
crates/fj-viewer/src/graphics/model.rs
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use tobj::LoadError;
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
|
use super::texture::{self, LoadTextureError};
|
||||||
|
use crate::assets::Assets;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct ModelVertex {
|
||||||
|
pub position: [f32; 3],
|
||||||
|
pub tex_coords: [f32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModelVertex {
|
||||||
|
pub fn desc<'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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Model {
|
||||||
|
pub meshes: Vec<Mesh>,
|
||||||
|
pub materials: Vec<Material>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Material {
|
||||||
|
pub name: String,
|
||||||
|
pub diffuse_texture: super::texture::Texture,
|
||||||
|
pub bind_group: wgpu::BindGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Mesh {
|
||||||
|
pub name: String,
|
||||||
|
pub vertex_buffer: wgpu::Buffer,
|
||||||
|
pub index_buffer: wgpu::Buffer,
|
||||||
|
pub num_elements: u32,
|
||||||
|
pub material: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum LoadModelError {
|
||||||
|
#[error("Object loading error")]
|
||||||
|
ObjLoad(#[from] LoadError),
|
||||||
|
|
||||||
|
#[error("Load texture error")]
|
||||||
|
Texture(#[from] LoadTextureError),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_model(
|
||||||
|
file_name: &str,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
layout: &wgpu::BindGroupLayout,
|
||||||
|
) -> Result<Model, LoadModelError> {
|
||||||
|
let assets = Assets::get_instance();
|
||||||
|
|
||||||
|
let (models, obj_materials) = tobj::load_obj_buf(
|
||||||
|
&mut assets.get_asset(file_name),
|
||||||
|
&tobj::LoadOptions {
|
||||||
|
triangulate: true,
|
||||||
|
single_index: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
|p| {
|
||||||
|
tobj::load_mtl_buf(
|
||||||
|
&mut assets.get_asset(
|
||||||
|
p.file_name()
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.expect("OsStr could not be converted to a str"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut materials = Vec::new();
|
||||||
|
for m in obj_materials? {
|
||||||
|
let texture_data: &[u8] = assets.get_asset(m.diffuse_texture.as_str());
|
||||||
|
|
||||||
|
let diffuse_texture = texture::Texture::from_bytes(
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
texture_data,
|
||||||
|
file_name,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
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: m.name,
|
||||||
|
diffuse_texture,
|
||||||
|
bind_group,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let meshes = models
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| {
|
||||||
|
let vertices = (0..m.mesh.positions.len() / 3)
|
||||||
|
.map(|i| 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],
|
||||||
|
1.0 - m.mesh.texcoords[i * 2 + 1],
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let vertex_buffer =
|
||||||
|
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some(&format!("{file_name:?} Vertex Buffer")),
|
||||||
|
contents: bytemuck::cast_slice(&vertices),
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
});
|
||||||
|
let index_buffer =
|
||||||
|
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some(&format!("{file_name:?} Index Buffer")),
|
||||||
|
contents: bytemuck::cast_slice(&m.mesh.indices),
|
||||||
|
usage: wgpu::BufferUsages::INDEX,
|
||||||
|
});
|
||||||
|
|
||||||
|
Mesh {
|
||||||
|
name: file_name.to_string(),
|
||||||
|
vertex_buffer,
|
||||||
|
index_buffer,
|
||||||
|
num_elements: m.mesh.indices.len() as u32,
|
||||||
|
material: m.mesh.material_id.unwrap_or(0),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(Model { meshes, materials })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DrawModel<'a> {
|
||||||
|
fn draw_mesh(&mut self, mesh: &'a Mesh, material: &'a Material);
|
||||||
|
fn draw_mesh_instanced(
|
||||||
|
&mut self,
|
||||||
|
mesh: &'a Mesh,
|
||||||
|
material: &'a Material,
|
||||||
|
instances: Range<u32>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn draw_model(&mut self, model: &'a Model);
|
||||||
|
fn draw_model_instanced(&mut self, model: &'a Model, instances: Range<u32>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> DrawModel<'b> for wgpu::RenderPass<'a>
|
||||||
|
where
|
||||||
|
'b: 'a,
|
||||||
|
{
|
||||||
|
fn draw_mesh(&mut self, mesh: &'b Mesh, material: &'b Material) {
|
||||||
|
self.draw_mesh_instanced(mesh, material, 0..1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_mesh_instanced(
|
||||||
|
&mut self,
|
||||||
|
mesh: &'b Mesh,
|
||||||
|
material: &'b Material,
|
||||||
|
instances: Range<u32>,
|
||||||
|
) {
|
||||||
|
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.draw_indexed(0..mesh.num_elements, 0, instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_model(&mut self, model: &'b Model) {
|
||||||
|
self.draw_model_instanced(model, 0..1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_model_instanced(
|
||||||
|
&mut self,
|
||||||
|
model: &'b Model,
|
||||||
|
instances: Range<u32>,
|
||||||
|
) {
|
||||||
|
for mesh in &model.meshes {
|
||||||
|
let material = &model.materials[mesh.material];
|
||||||
|
self.draw_mesh_instanced(mesh, material, instances.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
220
crates/fj-viewer/src/graphics/navigation_cube.rs
Normal file
220
crates/fj-viewer/src/graphics/navigation_cube.rs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
use fj_math::Transform;
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
|
use super::model::{self, load_model, DrawModel, Model};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NavigationCubeRenderer {
|
||||||
|
cube_model: Model,
|
||||||
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
|
mvp_matrix_bind_group: wgpu::BindGroup,
|
||||||
|
mvp_matrix_buffer: wgpu::Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SCALE_FACTOR: f64 = 0.13;
|
||||||
|
const CUBE_TRANSLATION: [f64; 3] = [0.8, 0.7, 0.0];
|
||||||
|
|
||||||
|
impl NavigationCubeRenderer {
|
||||||
|
pub fn new(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
config: &wgpu::SurfaceConfiguration,
|
||||||
|
aspect_ratio: f64,
|
||||||
|
) -> Self {
|
||||||
|
let texture_bind_group_layout =
|
||||||
|
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(
|
||||||
|
wgpu::SamplerBindingType::Filtering,
|
||||||
|
),
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: Some("texture_bind_group_layout"),
|
||||||
|
});
|
||||||
|
|
||||||
|
let mvp_matrix =
|
||||||
|
Self::get_mvp_matrix(Transform::identity(), aspect_ratio);
|
||||||
|
|
||||||
|
let mvp_matrix_buffer =
|
||||||
|
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("Model Matrix Buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&[mvp_matrix]),
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM
|
||||||
|
| wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
let mvp_matrix_bind_group_layout =
|
||||||
|
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("mvp_matrix_group_layout"),
|
||||||
|
});
|
||||||
|
let mvp_matrix_bind_group =
|
||||||
|
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &mvp_matrix_bind_group_layout,
|
||||||
|
entries: &[wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: mvp_matrix_buffer.as_entire_binding(),
|
||||||
|
}],
|
||||||
|
label: Some("mvp_matrix_bind_group"),
|
||||||
|
});
|
||||||
|
|
||||||
|
let shader =
|
||||||
|
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("Shadow Display Shader"),
|
||||||
|
source: wgpu::ShaderSource::Wgsl(
|
||||||
|
include_str!("navigation_cube.wgsl").into(),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
let render_pipeline_layout =
|
||||||
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Render Pipeline Layout"),
|
||||||
|
bind_group_layouts: &[
|
||||||
|
&texture_bind_group_layout,
|
||||||
|
&mvp_matrix_bind_group_layout,
|
||||||
|
],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
let render_pipeline =
|
||||||
|
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Navigation Cube Renderer"),
|
||||||
|
layout: Some(&render_pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "vertex",
|
||||||
|
buffers: &[model::ModelVertex::desc()],
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "fragment",
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: 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::POLYGON_MODE_LINE
|
||||||
|
// or Features::POLYGON_MODE_POINT
|
||||||
|
polygon_mode: wgpu::PolygonMode::Fill,
|
||||||
|
// Requires Features::DEPTH_CLIP_CONTROL
|
||||||
|
unclipped_depth: false,
|
||||||
|
// Requires Features::CONSERVATIVE_RASTERIZATION
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
count: 1,
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
multiview: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let cube_model =
|
||||||
|
load_model("cube.obj", device, queue, &texture_bind_group_layout)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cube_model,
|
||||||
|
render_pipeline,
|
||||||
|
mvp_matrix_bind_group,
|
||||||
|
mvp_matrix_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(
|
||||||
|
&mut self,
|
||||||
|
view: &wgpu::TextureView,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
aspect_ratio: f64,
|
||||||
|
rotation: Transform,
|
||||||
|
) {
|
||||||
|
let mvp_matrix = Self::get_mvp_matrix(rotation, aspect_ratio);
|
||||||
|
queue.write_buffer(
|
||||||
|
&self.mvp_matrix_buffer,
|
||||||
|
0,
|
||||||
|
bytemuck::cast_slice(&[mvp_matrix]),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut render_pass =
|
||||||
|
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: Some("Depth Visual Render Pass"),
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Load,
|
||||||
|
store: true,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
});
|
||||||
|
render_pass.set_pipeline(&self.render_pipeline);
|
||||||
|
render_pass.set_bind_group(1, &self.mvp_matrix_bind_group, &[]);
|
||||||
|
render_pass.draw_model(&self.cube_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mvp_matrix(rotation: Transform, aspect_ratio: f64) -> [f32; 16] {
|
||||||
|
let scale = Transform::scale(SCALE_FACTOR);
|
||||||
|
let world_translation = Transform::translation([0.0, 0.0, -1.0]);
|
||||||
|
|
||||||
|
let mut model_matrix = Transform::identity();
|
||||||
|
model_matrix = model_matrix * world_translation;
|
||||||
|
model_matrix = model_matrix * rotation;
|
||||||
|
model_matrix = model_matrix * scale;
|
||||||
|
|
||||||
|
let perspective =
|
||||||
|
nalgebra::Perspective3::new(aspect_ratio, 30.0, 0.1, 2.0);
|
||||||
|
|
||||||
|
let view_matrix = nalgebra::Matrix4::look_at_lh(
|
||||||
|
&nalgebra::Point3::new(0.0, 0.0, 0.0),
|
||||||
|
&nalgebra::Point3::new(0.0, 0.0, 1.0),
|
||||||
|
&nalgebra::Vector3::new(0.0, -1.0, 0.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
let screen_translation = Transform::translation(CUBE_TRANSLATION);
|
||||||
|
|
||||||
|
let matrix = screen_translation.get_inner().matrix()
|
||||||
|
* *perspective.to_projective().matrix()
|
||||||
|
* view_matrix
|
||||||
|
* model_matrix.get_inner().matrix();
|
||||||
|
|
||||||
|
let mut mat = [0.; 16];
|
||||||
|
mat.copy_from_slice(matrix.as_slice());
|
||||||
|
mat.map(|x| x as f32)
|
||||||
|
}
|
||||||
|
}
|
36
crates/fj-viewer/src/graphics/navigation_cube.wgsl
Normal file
36
crates/fj-viewer/src/graphics/navigation_cube.wgsl
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Vertex shader
|
||||||
|
|
||||||
|
@group(1) @binding(0)
|
||||||
|
var<uniform> mvp_matrix: mat4x4<f32>;
|
||||||
|
|
||||||
|
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>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vertex(
|
||||||
|
model: VertexInput,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.tex_coords = model.tex_coords;
|
||||||
|
out.clip_position = mvp_matrix * vec4<f32>(model.position, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fragment shader
|
||||||
|
|
||||||
|
@group(0) @binding(0)
|
||||||
|
var t_diffuse: texture_2d<f32>;
|
||||||
|
@group(0)@binding(1)
|
||||||
|
var s_diffuse: sampler;
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
|
||||||
|
}
|
@ -13,8 +13,9 @@ use crate::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
draw_config::DrawConfig, drawables::Drawables, geometries::Geometries,
|
draw_config::DrawConfig, drawables::Drawables, geometries::Geometries,
|
||||||
pipelines::Pipelines, transform::Transform, uniforms::Uniforms,
|
navigation_cube::NavigationCubeRenderer, pipelines::Pipelines,
|
||||||
vertices::Vertices, DEPTH_FORMAT, SAMPLE_COUNT,
|
transform::Transform, uniforms::Uniforms, vertices::Vertices, DEPTH_FORMAT,
|
||||||
|
SAMPLE_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Graphics rendering state and target abstraction
|
/// Graphics rendering state and target abstraction
|
||||||
@ -34,6 +35,8 @@ pub struct Renderer {
|
|||||||
|
|
||||||
geometries: Geometries,
|
geometries: Geometries,
|
||||||
pipelines: Pipelines,
|
pipelines: Pipelines,
|
||||||
|
|
||||||
|
navigation_cube_renderer: NavigationCubeRenderer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
@ -183,6 +186,13 @@ impl Renderer {
|
|||||||
let pipelines =
|
let pipelines =
|
||||||
Pipelines::new(&device, &bind_group_layout, color_format);
|
Pipelines::new(&device, &bind_group_layout, color_format);
|
||||||
|
|
||||||
|
let navigation_cube_renderer = NavigationCubeRenderer::new(
|
||||||
|
&device,
|
||||||
|
&queue,
|
||||||
|
&surface_config,
|
||||||
|
800.0 / 600.0,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
surface,
|
surface,
|
||||||
features,
|
features,
|
||||||
@ -198,6 +208,8 @@ impl Renderer {
|
|||||||
|
|
||||||
geometries,
|
geometries,
|
||||||
pipelines,
|
pipelines,
|
||||||
|
|
||||||
|
navigation_cube_renderer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +343,14 @@ impl Renderer {
|
|||||||
gui.draw(&mut render_pass, &clipped_primitives, &screen_descriptor);
|
gui.draw(&mut render_pass, &clipped_primitives, &screen_descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.navigation_cube_renderer.draw(
|
||||||
|
&color_view,
|
||||||
|
&mut encoder,
|
||||||
|
&self.queue,
|
||||||
|
aspect_ratio,
|
||||||
|
camera.rotation,
|
||||||
|
);
|
||||||
|
|
||||||
let command_buffer = encoder.finish();
|
let command_buffer = encoder.finish();
|
||||||
self.queue.submit(Some(command_buffer));
|
self.queue.submit(Some(command_buffer));
|
||||||
|
|
||||||
|
86
crates/fj-viewer/src/graphics/texture.rs
Normal file
86
crates/fj-viewer/src/graphics/texture.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
use image::{GenericImageView, ImageError};
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Texture {
|
||||||
|
pub texture: wgpu::Texture,
|
||||||
|
pub view: wgpu::TextureView,
|
||||||
|
pub sampler: wgpu::Sampler,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum LoadTextureError {
|
||||||
|
#[error("Image processing error")]
|
||||||
|
ImageError(#[from] ImageError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Texture {
|
||||||
|
pub fn from_bytes(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
bytes: &[u8],
|
||||||
|
label: &str,
|
||||||
|
) -> Result<Self, LoadTextureError> {
|
||||||
|
let img = image::load_from_memory(bytes)?;
|
||||||
|
Ok(Self::from_image(device, queue, &img, Some(label)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_image(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
img: &image::DynamicImage,
|
||||||
|
label: Option<&str>,
|
||||||
|
) -> Self {
|
||||||
|
let dimensions = img.dimensions();
|
||||||
|
let rgba = img.to_rgba8();
|
||||||
|
|
||||||
|
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: NonZeroU32::new(4 * dimensions.0),
|
||||||
|
rows_per_image: 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()
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
texture,
|
||||||
|
view,
|
||||||
|
sampler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
mod assets;
|
||||||
mod camera;
|
mod camera;
|
||||||
mod graphics;
|
mod graphics;
|
||||||
mod gui;
|
mod gui;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user