mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-21 22:38:41 -06:00
kitty? kitty!
This commit is contained in:
parent
3f0697d573
commit
eec672d665
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -1242,6 +1242,7 @@ dependencies = [
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"strum",
|
"strum",
|
||||||
"tinyset",
|
"tinyset",
|
||||||
|
"tobj",
|
||||||
"uflow",
|
"uflow",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
@ -2420,6 +2421,15 @@ dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tobj"
|
||||||
|
version = "4.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3bd4ba05f29e4c65b6c0c11a58b6465ffa820bac890d76ad407b4e81d8372e8"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.12"
|
version = "0.8.12"
|
||||||
|
|
BIN
assets-src/playermodel1.blend
Normal file
BIN
assets-src/playermodel1.blend
Normal file
Binary file not shown.
64
assets/playermodel1.obj
Normal file
64
assets/playermodel1.obj
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# Blender 4.0.0 Beta
|
||||||
|
# www.blender.org
|
||||||
|
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
|
||||||
|
v 1.000000 1.500000 -1.000000
|
||||||
|
v 1.000000 1.500000 1.000000
|
||||||
|
v 1.000000 1.000000 -0.333333
|
||||||
|
v 1.000000 1.000000 0.333333
|
||||||
|
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
|
||||||
|
vt 0.204555 0.291387
|
||||||
|
vt 0.043204 0.462923
|
||||||
|
vt 0.043204 0.291387
|
||||||
|
vt 0.259623 0.207472
|
||||||
|
vt 0.024467 0.457472
|
||||||
|
vt 0.024467 0.207472
|
||||||
|
vt 0.177715 0.183914
|
||||||
|
vt 0.010921 0.538561
|
||||||
|
vt 0.010921 0.183914
|
||||||
|
vt 0.246583 0.218979
|
||||||
|
vt 0.011426 0.468979
|
||||||
|
vt 0.011426 0.218979
|
||||||
|
vt 0.896961 0.811182
|
||||||
|
vt 0.168955 0.037222
|
||||||
|
vt 0.896961 0.037221
|
||||||
|
vt 0.177715 0.538561
|
||||||
|
vt 0.010921 0.361238
|
||||||
|
vt 0.168955 0.811182
|
||||||
|
vt 0.411624 0.811182
|
||||||
|
vt 0.204555 0.462923
|
||||||
|
vt 0.259623 0.457472
|
||||||
|
vt 0.246583 0.468979
|
||||||
|
vt 0.177715 0.361238
|
||||||
|
vt 0.896961 0.990308
|
||||||
|
vt 0.654292 0.811182
|
||||||
|
vt 0.168955 0.990308
|
||||||
|
s 0
|
||||||
|
f 5/1/1 3/2/1 1/3/1
|
||||||
|
f 3/4/2 8/5/2 4/6/2
|
||||||
|
f 7/7/3 6/8/3 8/9/3
|
||||||
|
f 2/10/4 8/11/4 6/12/4
|
||||||
|
f 1/13/5 4/14/5 2/15/5
|
||||||
|
f 5/16/6 2/17/6 6/8/6
|
||||||
|
f 3/18/1 1/13/1 12/19/1
|
||||||
|
f 5/1/1 7/20/1 3/2/1
|
||||||
|
f 3/4/2 7/21/2 8/5/2
|
||||||
|
f 7/7/3 5/16/3 6/8/3
|
||||||
|
f 2/10/4 4/22/4 8/11/4
|
||||||
|
f 1/13/5 3/18/5 4/14/5
|
||||||
|
f 5/16/6 1/23/6 2/17/6
|
||||||
|
f 1/13/5 9/24/5 11/25/5
|
||||||
|
f 12/19/5 10/26/5 3/18/5
|
||||||
|
f 1/13/5 11/25/5 12/19/5
|
BIN
assets/playermodel1.png
Normal file
BIN
assets/playermodel1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 137 KiB |
|
@ -38,7 +38,7 @@ tinyset = "0.4"
|
||||||
serde_json = { version = "1.0", optional = true } #only used for `generate_visualizer_data`
|
serde_json = { version = "1.0", optional = true } #only used for `generate_visualizer_data`
|
||||||
rand = { version = "0.8", features = ["alloc", "small_rng"]}
|
rand = { version = "0.8", features = ["alloc", "small_rng"]}
|
||||||
atomic = "0.6"
|
atomic = "0.6"
|
||||||
|
tobj = "4.0"
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
android-activity = "0.6"
|
android-activity = "0.6"
|
||||||
|
|
40
kubi/shaders/entities.wgsl
Normal file
40
kubi/shaders/entities.wgsl
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
struct CameraUniform {
|
||||||
|
view_proj: mat4x4<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
@group(1) @binding(0)
|
||||||
|
var<uniform> camera: CameraUniform;
|
||||||
|
|
||||||
|
struct VertexInput {
|
||||||
|
@location(0) uv: vec2<f32>,
|
||||||
|
@location(1) position: vec3<f32>,
|
||||||
|
@location(2) normal: vec3<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) clip_position: vec4<f32>,
|
||||||
|
@location(0) uv: vec2<f32>,
|
||||||
|
@location(1) normal: vec3<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(
|
||||||
|
in: VertexInput,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.clip_position = camera.view_proj * vec4<f32>(in.position, 1.0);
|
||||||
|
out.uv = in.uv;
|
||||||
|
out.normal = in.normal;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0)
|
||||||
|
var t_diffuse: texture_2d<f32>;
|
||||||
|
|
||||||
|
@group(0) @binding(1)
|
||||||
|
var s_diffuse: sampler;
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
return textureSample(t_diffuse, s_diffuse, in.uv);
|
||||||
|
}
|
|
@ -1,11 +1,35 @@
|
||||||
use std::{io::{BufReader, Read}, path::Path};
|
use std::{io::{BufReader, Read}, path::{Path, PathBuf}};
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
use hui::text::FontHandle;
|
use hui::text::FontHandle;
|
||||||
use shipyard::{AllStoragesView, NonSendSync, Unique, UniqueView, UniqueViewMut};
|
use shipyard::{AllStoragesView, NonSendSync, Unique, UniqueView, UniqueViewMut};
|
||||||
use kubi_shared::block::BlockTexture;
|
use kubi_shared::block::BlockTexture;
|
||||||
use crate::{filesystem::AssetManager, hui_integration::UiState, rendering::Renderer};
|
use crate::{filesystem::AssetManager, hui_integration::UiState, rendering::{BufferPair, Renderer}};
|
||||||
|
|
||||||
mod texture;
|
//TODO move to rendering module
|
||||||
use texture::load_texture2darray_prefab;
|
|
||||||
|
mod loader;
|
||||||
|
use loader::{load_texture2darray_prefab, load_texture2d_prefab, load_obj_prefab};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, Pod, Zeroable)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct ModelVertex {
|
||||||
|
pub tex_coords: [f32; 2],
|
||||||
|
pub position: [f32; 3],
|
||||||
|
pub _padding: u32,
|
||||||
|
pub normal: [f32; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModelVertex {
|
||||||
|
pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout {
|
||||||
|
array_stride: std::mem::size_of::<ModelVertex>() as wgpu::BufferAddress,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &wgpu::vertex_attr_array![
|
||||||
|
0 => Float32x2,
|
||||||
|
1 => Float32x3,
|
||||||
|
2 => Float32x3,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub trait AssetPaths {
|
pub trait AssetPaths {
|
||||||
fn file_name(self) -> &'static str;
|
fn file_name(self) -> &'static str;
|
||||||
|
@ -36,10 +60,14 @@ impl AssetPaths for BlockTexture {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Unique)]
|
#[derive(Unique)]
|
||||||
pub struct TexturePrefabs {
|
pub struct GpuPrefabs {
|
||||||
pub block_diffuse_texture: wgpu::Texture,
|
pub block_diffuse_texture: wgpu::Texture,
|
||||||
pub block_diffuse_bind_group_layout: wgpu::BindGroupLayout,
|
pub block_diffuse_bind_group_layout: wgpu::BindGroupLayout,
|
||||||
pub block_diffuse_bind_group: wgpu::BindGroup,
|
pub block_diffuse_bind_group: wgpu::BindGroup,
|
||||||
|
pub player_model_diffuse_texture: wgpu::Texture,
|
||||||
|
pub player_model_diffuse_bind_group_layout: wgpu::BindGroupLayout,
|
||||||
|
pub player_model_diffuse_bind_group: wgpu::BindGroup,
|
||||||
|
pub player_model: BufferPair,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Unique)]
|
#[derive(Unique)]
|
||||||
|
@ -110,10 +138,69 @@ pub fn load_prefabs(
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
storages.add_unique_non_send_sync(TexturePrefabs {
|
|
||||||
|
let player_model_diffuse_texture = load_texture2d_prefab(&renderer, &assman, &PathBuf::from("playermodel1.png"));
|
||||||
|
let player_model_diffuse_view = player_model_diffuse_texture.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
label: Some("player_model_texture_view"),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let player_model_diffuse_sampler = renderer.device().create_sampler(&wgpu::SamplerDescriptor {
|
||||||
|
label: Some("player_model_sampler"),
|
||||||
|
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,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let player_model_diffuse_bind_group_layout = renderer.device()
|
||||||
|
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("player_model_bind_group_layout"),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
multisampled: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||||
|
count: None,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
let player_model_diffuse_bind_group = renderer.device().create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: Some("player_model_bind_group"),
|
||||||
|
layout: &player_model_diffuse_bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&player_model_diffuse_view),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&player_model_diffuse_sampler),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
let player_model = load_obj_prefab(&renderer, &assman, &PathBuf::from("playermodel1.obj"));
|
||||||
|
|
||||||
|
storages.add_unique_non_send_sync(GpuPrefabs {
|
||||||
block_diffuse_texture,
|
block_diffuse_texture,
|
||||||
block_diffuse_bind_group_layout,
|
block_diffuse_bind_group_layout,
|
||||||
block_diffuse_bind_group,
|
block_diffuse_bind_group,
|
||||||
|
player_model_diffuse_texture,
|
||||||
|
player_model_diffuse_bind_group_layout,
|
||||||
|
player_model_diffuse_bind_group,
|
||||||
|
player_model,
|
||||||
});
|
});
|
||||||
|
|
||||||
log::info!("Loading the UI stuff...");
|
log::info!("Loading the UI stuff...");
|
||||||
|
|
164
kubi/src/prefabs/loader.rs
Normal file
164
kubi/src/prefabs/loader.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
use glam::UVec2;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use wgpu::util::{DeviceExt, TextureDataOrder};
|
||||||
|
use std::{io::{BufReader, Read}, path::{Path, PathBuf}};
|
||||||
|
use crate::{filesystem::AssetManager, prefabs::ModelVertex, rendering::{BufferPair, Renderer}};
|
||||||
|
use super::AssetPaths;
|
||||||
|
|
||||||
|
pub fn load_texture2darray_prefab<T: AssetPaths + IntoEnumIterator>(
|
||||||
|
renderer: &Renderer,
|
||||||
|
assman: &AssetManager,
|
||||||
|
directory: PathBuf,
|
||||||
|
) -> wgpu::Texture {
|
||||||
|
log::info!("started loading {}", directory.as_os_str().to_str().unwrap());
|
||||||
|
|
||||||
|
//Load raw images
|
||||||
|
let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect();
|
||||||
|
let raw_images: Vec<(Vec<u8>, UVec2)> = tex_files.par_iter().map(|&file_name| {
|
||||||
|
log::info!("loading texture {}", file_name);
|
||||||
|
|
||||||
|
//Get path to the image and open the file
|
||||||
|
let reader = {
|
||||||
|
let path = directory.join(file_name);
|
||||||
|
BufReader::new(assman.open_asset(&path).expect("Failed to open texture file"))
|
||||||
|
};
|
||||||
|
|
||||||
|
//Parse image data
|
||||||
|
let (image_data, dimensions) = {
|
||||||
|
let image = image::load(
|
||||||
|
reader,
|
||||||
|
image::ImageFormat::Png
|
||||||
|
).unwrap().to_rgba8();
|
||||||
|
let dimensions = image.dimensions();
|
||||||
|
(image.into_raw(), dimensions)
|
||||||
|
};
|
||||||
|
(image_data, UVec2::from(dimensions))
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
assert!(!raw_images.is_empty(), "no images loaded");
|
||||||
|
//TODO: check same size
|
||||||
|
|
||||||
|
log::info!("done loading texture files, uploading to the gpu");
|
||||||
|
|
||||||
|
let size = raw_images[0].1;
|
||||||
|
let layers = raw_images.len() as u32;
|
||||||
|
|
||||||
|
//Concat data into a single vec
|
||||||
|
let mut data = Vec::with_capacity((size.x * size.y * layers * 4) as usize);
|
||||||
|
for (layer_data, _) in raw_images {
|
||||||
|
data.extend_from_slice(&layer_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Upload images to the GPU
|
||||||
|
let label = format!("texture2darray_prefab_{}", directory.as_os_str().to_str().unwrap());
|
||||||
|
let desc = &wgpu::TextureDescriptor {
|
||||||
|
label: Some(&label),
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: size.x,
|
||||||
|
height: size.y,
|
||||||
|
depth_or_array_layers: layers,
|
||||||
|
},
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
view_formats: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.device().create_texture_with_data(
|
||||||
|
renderer.queue(),
|
||||||
|
desc,
|
||||||
|
TextureDataOrder::MipMajor,
|
||||||
|
&data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_texture2d_prefab(
|
||||||
|
renderer: &Renderer,
|
||||||
|
assman: &AssetManager,
|
||||||
|
path: &Path,
|
||||||
|
) -> wgpu::Texture {
|
||||||
|
let image = image::load(
|
||||||
|
BufReader::new(assman.open_asset(path).expect("Failed to open texture file")),
|
||||||
|
image::ImageFormat::Png
|
||||||
|
).unwrap().to_rgba8();
|
||||||
|
let size = image.dimensions();
|
||||||
|
let data = image.into_raw();
|
||||||
|
|
||||||
|
let label = format!("texture2d_prefab_{}", path.file_name().unwrap().to_str().unwrap());
|
||||||
|
let desc = wgpu::TextureDescriptor {
|
||||||
|
label: Some(&label),
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: size.0,
|
||||||
|
height: size.1,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
view_formats: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.device().create_texture_with_data(
|
||||||
|
renderer.queue(),
|
||||||
|
&desc,
|
||||||
|
TextureDataOrder::MipMajor,
|
||||||
|
&data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_obj_prefab(
|
||||||
|
renderer: &Renderer,
|
||||||
|
assman: &AssetManager,
|
||||||
|
path: &Path,
|
||||||
|
) -> BufferPair {
|
||||||
|
let mut reader = BufReader::new(
|
||||||
|
assman.open_asset(path).expect("Failed to open texture file")
|
||||||
|
);
|
||||||
|
|
||||||
|
let (model, _) = tobj::load_obj_buf(
|
||||||
|
&mut reader,
|
||||||
|
&tobj::GPU_LOAD_OPTIONS,
|
||||||
|
|_| unimplemented!()
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(model.len(), 1, "only single model supported at the moment, sowwy :3");
|
||||||
|
let mesh = &model[0].mesh;
|
||||||
|
debug_assert!(mesh.normal_indices.is_empty() && mesh.texcoord_indices.is_empty(), "forgor single_index");
|
||||||
|
|
||||||
|
let tex_coords = bytemuck::cast_slice::<f32, [f32; 2]>(&mesh.texcoords);
|
||||||
|
let positions = bytemuck::cast_slice::<f32, [f32; 3]>(&mesh.positions);
|
||||||
|
let normals = bytemuck::cast_slice::<f32, [f32; 3]>(&mesh.normals);
|
||||||
|
|
||||||
|
let vertex_buffer: Vec<_> = (0..positions.len()).map(|i| {
|
||||||
|
ModelVertex {
|
||||||
|
tex_coords: [tex_coords[i][0], 1. - tex_coords[i][1]],
|
||||||
|
position: positions[i],
|
||||||
|
_padding: 0,
|
||||||
|
normal: normals[i],
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let vertex_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("obj_vertex_buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&vertex_buffer),
|
||||||
|
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX,
|
||||||
|
});
|
||||||
|
|
||||||
|
let index_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("obj_index_buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&mesh.indices),
|
||||||
|
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::INDEX,
|
||||||
|
});
|
||||||
|
|
||||||
|
BufferPair {
|
||||||
|
vertex: vertex_buffer,
|
||||||
|
vertex_len: positions.len() as u32,
|
||||||
|
index: index_buffer,
|
||||||
|
index_len: mesh.indices.len() as u32,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,75 +0,0 @@
|
||||||
use glam::UVec2;
|
|
||||||
use strum::IntoEnumIterator;
|
|
||||||
use rayon::prelude::*;
|
|
||||||
use wgpu::util::{DeviceExt, TextureDataOrder};
|
|
||||||
use std::{io::BufReader, path::PathBuf};
|
|
||||||
use crate::{filesystem::AssetManager, rendering::Renderer};
|
|
||||||
use super::AssetPaths;
|
|
||||||
|
|
||||||
pub fn load_texture2darray_prefab<T: AssetPaths + IntoEnumIterator>(
|
|
||||||
renderer: &Renderer,
|
|
||||||
assman: &AssetManager,
|
|
||||||
directory: PathBuf,
|
|
||||||
) -> wgpu::Texture {
|
|
||||||
log::info!("started loading {}", directory.as_os_str().to_str().unwrap());
|
|
||||||
|
|
||||||
//Load raw images
|
|
||||||
let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect();
|
|
||||||
let raw_images: Vec<(Vec<u8>, UVec2)> = tex_files.par_iter().map(|&file_name| {
|
|
||||||
log::info!("loading texture {}", file_name);
|
|
||||||
|
|
||||||
//Get path to the image and open the file
|
|
||||||
let reader = {
|
|
||||||
let path = directory.join(file_name);
|
|
||||||
BufReader::new(assman.open_asset(&path).expect("Failed to open texture file"))
|
|
||||||
};
|
|
||||||
|
|
||||||
//Parse image data
|
|
||||||
let (image_data, dimensions) = {
|
|
||||||
let image = image::load(
|
|
||||||
reader,
|
|
||||||
image::ImageFormat::Png
|
|
||||||
).unwrap().to_rgba8();
|
|
||||||
let dimensions = image.dimensions();
|
|
||||||
(image.into_raw(), dimensions)
|
|
||||||
};
|
|
||||||
(image_data, UVec2::from(dimensions))
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
assert!(!raw_images.is_empty(), "no images loaded");
|
|
||||||
//TODO: check same size
|
|
||||||
|
|
||||||
log::info!("done loading texture files, uploading to the gpu");
|
|
||||||
|
|
||||||
let size = raw_images[0].1;
|
|
||||||
let layers = raw_images.len() as u32;
|
|
||||||
|
|
||||||
//Concat data into a single vec
|
|
||||||
let mut data = Vec::with_capacity((size.x * size.y * layers * 4) as usize);
|
|
||||||
for (layer_data, _) in raw_images {
|
|
||||||
data.extend_from_slice(&layer_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Upload images to the GPU
|
|
||||||
let desc = &wgpu::TextureDescriptor {
|
|
||||||
label: Some("block_diffuse_texture"),
|
|
||||||
size: wgpu::Extent3d {
|
|
||||||
width: size.x,
|
|
||||||
height: size.y,
|
|
||||||
depth_or_array_layers: layers,
|
|
||||||
},
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
view_formats: &[],
|
|
||||||
};
|
|
||||||
|
|
||||||
renderer.device().create_texture_with_data(
|
|
||||||
renderer.queue(),
|
|
||||||
desc,
|
|
||||||
TextureDataOrder::MipMajor,
|
|
||||||
&data
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ use crate::{events::WindowResizedEvent, hui_integration::kubi_ui_draw, state::is
|
||||||
mod renderer;
|
mod renderer;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
mod selection_box;
|
mod selection_box;
|
||||||
|
mod entities;
|
||||||
pub use renderer::Renderer;
|
pub use renderer::Renderer;
|
||||||
|
|
||||||
pub mod background;
|
pub mod background;
|
||||||
|
@ -35,8 +36,9 @@ pub fn init_rendering() -> Workload {
|
||||||
(
|
(
|
||||||
depth::init_depth_texture,
|
depth::init_depth_texture,
|
||||||
camera_uniform::init_camera_uniform_buffer,
|
camera_uniform::init_camera_uniform_buffer,
|
||||||
world::init_world_render_state, //req: depth, camera
|
|
||||||
primitives::init_primitives,
|
primitives::init_primitives,
|
||||||
|
world::init_world_render_state, //req: depth, camera
|
||||||
|
entities::init_entities_render_state, //req: depth, camera
|
||||||
selection_box::init_selection_box_render_state, //req: depth, camera, primitives
|
selection_box::init_selection_box_render_state, //req: depth, camera, primitives
|
||||||
).into_sequential_workload()
|
).into_sequential_workload()
|
||||||
}
|
}
|
||||||
|
@ -65,7 +67,6 @@ pub fn render_master(storages: AllStoragesViewMut) {
|
||||||
let surface_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let surface_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
let mut data = RenderCtx {
|
let mut data = RenderCtx {
|
||||||
//renderer: &renderer,
|
|
||||||
encoder: &mut encoder,
|
encoder: &mut encoder,
|
||||||
surface_view: &surface_view,
|
surface_view: &surface_view,
|
||||||
};
|
};
|
||||||
|
@ -74,8 +75,8 @@ pub fn render_master(storages: AllStoragesViewMut) {
|
||||||
if storages.run(is_ingame) {
|
if storages.run(is_ingame) {
|
||||||
storages.run_with_data(world::draw_world, &mut data);
|
storages.run_with_data(world::draw_world, &mut data);
|
||||||
storages.run_with_data(selection_box::draw_selection_box, &mut data);
|
storages.run_with_data(selection_box::draw_selection_box, &mut data);
|
||||||
|
storages.run_with_data(entities::render_entities, &mut data);
|
||||||
}
|
}
|
||||||
|
|
||||||
storages.run_with_data(kubi_ui_draw, &mut data);
|
storages.run_with_data(kubi_ui_draw, &mut data);
|
||||||
|
|
||||||
renderer.queue().submit([encoder.finish()]);
|
renderer.queue().submit([encoder.finish()]);
|
||||||
|
|
|
@ -1,58 +1,69 @@
|
||||||
// use shipyard::{NonSendSync, UniqueViewMut, UniqueView, View, IntoIter, IntoWithId};
|
use shipyard::{AllStoragesView, IntoIter, IntoWithId, Unique, UniqueView, View};
|
||||||
// use glium::{DepthTest, Depth, PolygonMode, BackfaceCullingMode, DrawParameters, Surface, uniform};
|
use kubi_shared::{entity::Entity, transform::Transform};
|
||||||
// use kubi_shared::{entity::Entity, transform::Transform};
|
use crate::{
|
||||||
// use crate::{
|
camera::Camera, prefabs::GpuPrefabs, settings::GameSettings
|
||||||
// prefabs::ColoredShaderPrefab,
|
};
|
||||||
// camera::Camera,
|
|
||||||
// settings::GameSettings
|
|
||||||
// };
|
|
||||||
// use super::{
|
|
||||||
// RenderTarget,
|
|
||||||
// primitives::cube::CenteredCubePrimitive
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // TODO: entity models
|
use super::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, RenderCtx};
|
||||||
// pub fn render_entities(
|
|
||||||
// mut target: NonSendSync<UniqueViewMut<RenderTarget>>,
|
|
||||||
// buffers: NonSendSync<UniqueView<CenteredCubePrimitive>>,
|
|
||||||
// program: NonSendSync<UniqueView<ColoredShaderPrefab>>,
|
|
||||||
// camera: View<Camera>,
|
|
||||||
// settings: UniqueView<GameSettings>,
|
|
||||||
// entities: View<Entity>,
|
|
||||||
// transform: View<Transform>,
|
|
||||||
// ) {
|
|
||||||
// let (camera_id, camera) = camera.iter().with_id().next().expect("No cameras in the scene");
|
|
||||||
|
|
||||||
// let draw_parameters = DrawParameters {
|
mod pipeline;
|
||||||
// depth: Depth {
|
|
||||||
// test: DepthTest::IfLess,
|
|
||||||
// write: true,
|
|
||||||
// ..Default::default()
|
|
||||||
// },
|
|
||||||
// multisampling: settings.msaa.is_some(),
|
|
||||||
// polygon_mode: PolygonMode::Fill,
|
|
||||||
// backface_culling: BackfaceCullingMode::CullClockwise,
|
|
||||||
// ..Default::default()
|
|
||||||
// };
|
|
||||||
// let view = camera.view_matrix.to_cols_array_2d();
|
|
||||||
// let perspective = camera.perspective_matrix.to_cols_array_2d();
|
|
||||||
|
|
||||||
// for (entity_id, (_, trans)) in (&entities, &transform).iter().with_id() {
|
#[derive(Unique)]
|
||||||
// //skip rendering camera holder (as the entity would block the view)
|
pub struct EntitiesRenderState {
|
||||||
// if entity_id == camera_id { continue }
|
pub pipeline: wgpu::RenderPipeline,
|
||||||
|
}
|
||||||
|
|
||||||
// //render entity
|
pub fn init_entities_render_state(storages: AllStoragesView) {
|
||||||
// target.0.draw(
|
storages.add_unique(EntitiesRenderState {
|
||||||
// &buffers.0,
|
pipeline: storages.run(pipeline::init_entities_pipeline),
|
||||||
// &buffers.1,
|
});
|
||||||
// &program.0,
|
}
|
||||||
// &uniform! {
|
|
||||||
// color: [1.0, 1.0, 1.0, 1.0_f32],
|
// TODO: entity models
|
||||||
// model: trans.0.to_cols_array_2d(),
|
pub fn render_entities(
|
||||||
// view: view,
|
ctx: &mut RenderCtx,
|
||||||
// perspective: perspective,
|
state: UniqueView<EntitiesRenderState>,
|
||||||
// },
|
depth: UniqueView<DepthTexture>,
|
||||||
// &draw_parameters
|
prefabs: UniqueView<GpuPrefabs>,
|
||||||
// ).unwrap();
|
camera_ubo: UniqueView<CameraUniformBuffer>,
|
||||||
// }
|
camera: View<Camera>,
|
||||||
// }
|
settings: UniqueView<GameSettings>,
|
||||||
|
entities: View<Entity>,
|
||||||
|
transform: View<Transform>,
|
||||||
|
) {
|
||||||
|
let mut rpass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: Some("rpass_draw_entities"),
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: ctx.surface_view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Load,
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||||
|
view: &depth.depth_view,
|
||||||
|
depth_ops: Some(wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Load,
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
}),
|
||||||
|
stencil_ops: None,
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
rpass.set_pipeline(&state.pipeline);
|
||||||
|
rpass.set_bind_group(0, &prefabs.player_model_diffuse_bind_group, &[]);
|
||||||
|
rpass.set_bind_group(1, &camera_ubo.camera_bind_group, &[]);
|
||||||
|
rpass.set_vertex_buffer(0, prefabs.player_model.vertex.slice(..));
|
||||||
|
rpass.set_index_buffer(prefabs.player_model.index.slice(..), wgpu::IndexFormat::Uint32);
|
||||||
|
rpass.draw_indexed(0..prefabs.player_model.index_len, 0, 0..1);
|
||||||
|
|
||||||
|
// let (camera_id, _camera) = camera.iter().with_id().next().expect("No cameras in the scene");
|
||||||
|
|
||||||
|
// for (entity_id, (_, trans)) in (&entities, &transform).iter().with_id() {
|
||||||
|
// //skip rendering camera holder (as the entity would block the view)
|
||||||
|
// if entity_id == camera_id { continue }
|
||||||
|
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
61
kubi/src/rendering/entities/pipeline.rs
Normal file
61
kubi/src/rendering/entities/pipeline.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
use shipyard::UniqueView;
|
||||||
|
use wgpu::include_wgsl;
|
||||||
|
use crate::{prefabs::{GpuPrefabs, ModelVertex}, rendering::{camera_uniform::CameraUniformBuffer, Renderer}};
|
||||||
|
|
||||||
|
pub fn init_entities_pipeline(
|
||||||
|
renderer: UniqueView<Renderer>,
|
||||||
|
prefabs: UniqueView<GpuPrefabs>,
|
||||||
|
camera_ubo: UniqueView<CameraUniformBuffer>,
|
||||||
|
) -> wgpu::RenderPipeline {
|
||||||
|
let module = renderer.device().create_shader_module(include_wgsl!("../../../shaders/entities.wgsl"));
|
||||||
|
|
||||||
|
let pipeline_layout = renderer.device().create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("entities_pipeline_layout"),
|
||||||
|
bind_group_layouts: &[
|
||||||
|
&prefabs.player_model_diffuse_bind_group_layout,
|
||||||
|
&camera_ubo.camera_bind_group_layout,
|
||||||
|
],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
renderer.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("entities_pipeline"),
|
||||||
|
layout: Some(&pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &module,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
entry_point: "vs_main",
|
||||||
|
buffers: &[
|
||||||
|
ModelVertex::LAYOUT,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &module,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
entry_point: "fs_main",
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: renderer.surface_config().format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::COLOR,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
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,
|
||||||
|
conservative: false,
|
||||||
|
unclipped_depth: false,
|
||||||
|
},
|
||||||
|
depth_stencil: Some(wgpu::DepthStencilState {
|
||||||
|
format: wgpu::TextureFormat::Depth32Float,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Less,
|
||||||
|
bias: wgpu::DepthBiasState::default(),
|
||||||
|
stencil: wgpu::StencilState::default(),
|
||||||
|
}),
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
})
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ pub fn draw_selection_box(
|
||||||
view: &depth.depth_view,
|
view: &depth.depth_view,
|
||||||
depth_ops: Some(wgpu::Operations {
|
depth_ops: Some(wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Load,
|
load: wgpu::LoadOp::Load,
|
||||||
store: wgpu::StoreOp::Discard,
|
store: wgpu::StoreOp::Store,
|
||||||
}),
|
}),
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -3,7 +3,7 @@ use shipyard::{AllStoragesView, IntoIter, NonSendSync, Unique, UniqueView, View}
|
||||||
use kubi_shared::chunk::CHUNK_SIZE;
|
use kubi_shared::chunk::CHUNK_SIZE;
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::Camera,
|
camera::Camera,
|
||||||
prefabs::TexturePrefabs,
|
prefabs::GpuPrefabs,
|
||||||
world::{ChunkMeshStorage, ChunkStorage},
|
world::{ChunkMeshStorage, ChunkStorage},
|
||||||
};
|
};
|
||||||
use super::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, RenderCtx};
|
use super::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, RenderCtx};
|
||||||
|
@ -30,7 +30,7 @@ pub fn draw_world(
|
||||||
state: UniqueView<WorldRenderState>,
|
state: UniqueView<WorldRenderState>,
|
||||||
camera_ubo: UniqueView<CameraUniformBuffer>,
|
camera_ubo: UniqueView<CameraUniformBuffer>,
|
||||||
depth: UniqueView<DepthTexture>,
|
depth: UniqueView<DepthTexture>,
|
||||||
textures: UniqueView<TexturePrefabs>,
|
textures: UniqueView<GpuPrefabs>,
|
||||||
camera: View<Camera>,
|
camera: View<Camera>,
|
||||||
chunks: UniqueView<ChunkStorage>,
|
chunks: UniqueView<ChunkStorage>,
|
||||||
meshes: NonSendSync<UniqueView<ChunkMeshStorage>>,
|
meshes: NonSendSync<UniqueView<ChunkMeshStorage>>,
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use shipyard::UniqueView;
|
use shipyard::UniqueView;
|
||||||
use crate::{
|
use crate::{
|
||||||
prefabs::TexturePrefabs,
|
prefabs::GpuPrefabs,
|
||||||
rendering::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, world::ChunkVertex, Renderer}
|
rendering::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, world::ChunkVertex, Renderer}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init_world_pipeline(
|
pub fn init_world_pipeline(
|
||||||
ren: UniqueView<Renderer>,
|
ren: UniqueView<Renderer>,
|
||||||
depth: UniqueView<DepthTexture>,
|
depth: UniqueView<DepthTexture>,
|
||||||
textures: UniqueView<TexturePrefabs>,
|
textures: UniqueView<GpuPrefabs>,
|
||||||
camera_ubo: UniqueView<CameraUniformBuffer>,
|
camera_ubo: UniqueView<CameraUniformBuffer>,
|
||||||
) -> wgpu::RenderPipeline {
|
) -> wgpu::RenderPipeline {
|
||||||
let shader = ren.device().create_shader_module(
|
let shader = ren.device().create_shader_module(
|
||||||
|
|
Loading…
Reference in a new issue