forked from itycodes/MineClone
parent
c9fdcfe008
commit
0e92480ce8
@ -0,0 +1,22 @@
|
|||||||
|
#version 450
|
||||||
|
// vim: ft=c
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 normal;
|
||||||
|
layout(location = 1) in vec4 pos_pre;
|
||||||
|
layout(location = 2) in vec4 view_orig;
|
||||||
|
|
||||||
|
layout(push_constant, std430) uniform pc {
|
||||||
|
layout(offset=48) vec4 data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(data.rgb*(1.0+dot(normal.xyz, normalize(vec3(-0.7, -0.5, -0.1))))/2.0, 1.0);
|
||||||
|
//if(pos_post.z <= 0.0) {
|
||||||
|
// outColor = vec4(1.0);
|
||||||
|
//}
|
||||||
|
//outColor = normal.xyz;
|
||||||
|
//outColor = vec4(vec3(1.0-gl_FragCoord.z), 1.0);
|
||||||
|
}
|
@ -0,0 +1,130 @@
|
|||||||
|
#version 450
|
||||||
|
// vim: ft=c
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
struct PosNorm {
|
||||||
|
vec4 pos;
|
||||||
|
vec4 norm;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, set = 0, binding = 0) buffer positions_buffer {
|
||||||
|
PosNorm posnrm[];
|
||||||
|
} pos;
|
||||||
|
|
||||||
|
layout(push_constant, std430) uniform pc {
|
||||||
|
layout(offset=0) vec4 cam_orig;
|
||||||
|
layout(offset=16) vec4 cam_rot;
|
||||||
|
layout(offset=32) uvec2 screen_res;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 normal;
|
||||||
|
layout (location = 1) out vec4 pos_pre;
|
||||||
|
layout (location = 2) out vec4 view_orig;
|
||||||
|
|
||||||
|
const float PI = 3.14159;
|
||||||
|
// Forgive me for I have sinned
|
||||||
|
const float TAU = PI*2.0;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// assign outs
|
||||||
|
normal = pos.posnrm[gl_VertexIndex].norm;
|
||||||
|
pos_pre = pos.posnrm[gl_VertexIndex].pos;
|
||||||
|
view_orig = cam_orig;
|
||||||
|
|
||||||
|
// define constants
|
||||||
|
const float zFar = 100.0;
|
||||||
|
const float zNear = 0.1;
|
||||||
|
|
||||||
|
// assign the transformee
|
||||||
|
gl_Position = pos.posnrm[gl_VertexIndex].pos;
|
||||||
|
|
||||||
|
mat4 fix_coordinates = mat4(
|
||||||
|
-1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, -1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, -1.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
mat4 view_orig = mat4(
|
||||||
|
1.0, 0.0, 0.0, cam_orig.x,
|
||||||
|
0.0, 1.0, 0.0, cam_orig.y,
|
||||||
|
0.0, 0.0, 1.0, cam_orig.z,
|
||||||
|
0.0, 0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
mat4 view_rot_xz = mat4(
|
||||||
|
cos(cam_rot.y), 0.0, sin(cam_rot.y), 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
-sin(cam_rot.y), 0.0, cos(cam_rot.y), 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
mat4 view_rot_yz = mat4(
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, cos(cam_rot.x), sin(cam_rot.x), 0.0,
|
||||||
|
0.0, -sin(cam_rot.x), cos(cam_rot.x), 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
mat4 project_aspect = mat4(
|
||||||
|
(float(screen_res.y)/float(screen_res.x)), 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
mat4 project_znear = mat4(
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, -zNear,
|
||||||
|
0.0, 0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
mat4 project_div = mat4(
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, tan((70.0/2.0)/360.0*TAU), 0.0
|
||||||
|
);
|
||||||
|
mat4 project_normal = mat4(
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0/zFar, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
// vulkan has inverted screen coordinates
|
||||||
|
// but we want regular mesh coordinates
|
||||||
|
// gl_Position.xyz *= -1.0
|
||||||
|
gl_Position *= fix_coordinates;
|
||||||
|
|
||||||
|
// apply view's origin transformation
|
||||||
|
//gl_Position.xyz += cam_orig.xyz;
|
||||||
|
gl_Position *= view_orig;
|
||||||
|
|
||||||
|
// apply view's xz rotation
|
||||||
|
//mat2 xz_rot;
|
||||||
|
//xz_rot[0] = vec2(cos(cam_rot.y), -sin(cam_rot.y));
|
||||||
|
//xz_rot[1] = vec2(sin(cam_rot.y), cos(cam_rot.y));
|
||||||
|
//gl_Position.xz *= inverse(xz_rot);
|
||||||
|
gl_Position *= view_rot_xz;
|
||||||
|
|
||||||
|
// apply view's yz rotation
|
||||||
|
//mat2 yz_rot;
|
||||||
|
//yz_rot[0] = vec2(cos(cam_rot.x), -sin(cam_rot.x));
|
||||||
|
//yz_rot[1] = vec2(sin(cam_rot.x), cos(cam_rot.x));
|
||||||
|
//gl_Position.yz *= inverse(yz_rot);
|
||||||
|
gl_Position *= view_rot_yz;
|
||||||
|
|
||||||
|
// aspect correction
|
||||||
|
//gl_Position.x *= (1080.0/1920.0);
|
||||||
|
gl_Position *= project_aspect;
|
||||||
|
|
||||||
|
// z near correction
|
||||||
|
//gl_Position.z -= zNear;
|
||||||
|
gl_Position *= project_znear;
|
||||||
|
|
||||||
|
// division by z
|
||||||
|
// has to be assigned by w so that the hardware performs the division AFTER clipping.
|
||||||
|
//gl_Position.w = (gl_Position.z*sin(140.0/360.0*TAU));
|
||||||
|
gl_Position *= project_div;
|
||||||
|
|
||||||
|
// z normalization
|
||||||
|
//gl_Position.z /= zFar;
|
||||||
|
gl_Position *= project_normal;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
|
use crate::{vec3, vector::Vector3};
|
||||||
|
|
||||||
|
pub struct Chunk {
|
||||||
|
blocks: [[[Block; 16]; 16]; 16],
|
||||||
|
pub chunk_coord: Vector3<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Chunk {
|
||||||
|
pub fn new(chunk_coord: Vector3<i32>) -> Self {
|
||||||
|
let mut blocks: [[[MaybeUninit<Block>; 16]; 16]; 16] =
|
||||||
|
unsafe { MaybeUninit::uninit().assume_init() };
|
||||||
|
|
||||||
|
blocks.iter_mut().for_each(|bs| {
|
||||||
|
bs.iter_mut().for_each(|bs| {
|
||||||
|
bs.iter_mut().for_each(|u| {
|
||||||
|
u.write(Block {
|
||||||
|
typ: BlockType::Air,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let blocks = unsafe {
|
||||||
|
std::mem::transmute::<[[[MaybeUninit<Block>; 16]; 16]; 16], [[[Block; 16]; 16]; 16]>(
|
||||||
|
blocks,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Chunk {
|
||||||
|
blocks,
|
||||||
|
chunk_coord,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_block(&mut self, block: Block, local_coord: Vector3<i32>) {
|
||||||
|
match local_coord {
|
||||||
|
Vector3 {
|
||||||
|
x: x @ 0..16,
|
||||||
|
y: y @ 0..16,
|
||||||
|
z: z @ 0..16,
|
||||||
|
} => self.blocks[x as usize][y as usize][z as usize] = block,
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_init(blocks: [[[Block; 16]; 16]; 16], chunk_coord: Vector3<i32>) -> Self {
|
||||||
|
Self {
|
||||||
|
blocks,
|
||||||
|
chunk_coord,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_block(&self, local_coord: Vector3<i32>) -> Option<&Block> {
|
||||||
|
match local_coord {
|
||||||
|
Vector3 {
|
||||||
|
x: x @ 0..16,
|
||||||
|
y: y @ 0..16,
|
||||||
|
z: z @ 0..16,
|
||||||
|
} => Some(&self.blocks[x as usize][y as usize][z as usize]),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blocks(&self) -> impl Iterator<Item = (&Block, Vector3<i32>)> {
|
||||||
|
let i = self
|
||||||
|
.blocks
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(x, bs)| {
|
||||||
|
bs.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(y, bs)| {
|
||||||
|
bs.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(z, b)| (b, vec3!(x as i32, y as i32, z as i32)))
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
})
|
||||||
|
.flatten();
|
||||||
|
i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Block {
|
||||||
|
pub typ: BlockType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Block {
|
||||||
|
pub fn is_transparent(&self) -> bool {
|
||||||
|
match self.typ {
|
||||||
|
BlockType::Air => true,
|
||||||
|
BlockType::Solid => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum BlockType {
|
||||||
|
Air,
|
||||||
|
Solid,
|
||||||
|
}
|
@ -0,0 +1,278 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use ash::vk;
|
||||||
|
|
||||||
|
use crate::{Game, LoadingWorld, RenderCtx, game::chunk::Chunk};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
MemType,
|
||||||
|
loading_world::WorldComponent,
|
||||||
|
mesher::{Mesh, PosNorm},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl WorldComponent for ChunkRender {
|
||||||
|
fn descriptors(&self) -> std::collections::HashMap<vk::DescriptorType, u32> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
map.insert(vk::DescriptorType::STORAGE_BUFFER, 1);
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn desc_layout(&self, ctx: &RenderCtx) -> vk::DescriptorSetLayout {
|
||||||
|
setup_desc_layout(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_desc_set(
|
||||||
|
&self,
|
||||||
|
ctx: &RenderCtx,
|
||||||
|
desc_set: vk::DescriptorSet,
|
||||||
|
skybox: (vk::ImageView, vk::Sampler),
|
||||||
|
) {
|
||||||
|
let buf_info = vk::DescriptorBufferInfo::default()
|
||||||
|
.buffer(self.mesh_buf)
|
||||||
|
.offset(0)
|
||||||
|
.range(vk::WHOLE_SIZE);
|
||||||
|
let buf_infos = [buf_info];
|
||||||
|
let buf_desc = vk::WriteDescriptorSet::default()
|
||||||
|
.dst_set(desc_set)
|
||||||
|
.dst_binding(0)
|
||||||
|
.dst_array_element(0)
|
||||||
|
.descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
|
||||||
|
.buffer_info(&buf_infos);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ctx.dev.update_descriptor_sets(&[buf_desc], &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pipeline(&self) -> (vk::Pipeline, vk::PipelineLayout) {
|
||||||
|
(self.pipeline, self.pipe_layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_constants(
|
||||||
|
&self,
|
||||||
|
camera: &crate::game::Camera,
|
||||||
|
res: [u32; 2],
|
||||||
|
base_color: [f32; 4],
|
||||||
|
) -> Vec<(vk::ShaderStageFlags, u32, Vec<u8>)> {
|
||||||
|
let mut constants = Vec::new();
|
||||||
|
let cam_data: Vec<u8> = (Vec::<f32>::from([
|
||||||
|
camera.origin.x,
|
||||||
|
camera.origin.y,
|
||||||
|
camera.origin.z,
|
||||||
|
0.0,
|
||||||
|
camera.rotation.x,
|
||||||
|
camera.rotation.y,
|
||||||
|
camera.rotation.z,
|
||||||
|
]))
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.to_ne_bytes())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_flattened();
|
||||||
|
constants.push((vk::ShaderStageFlags::VERTEX, 0, cam_data));
|
||||||
|
|
||||||
|
let screen_res: Vec<u8> = res
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.to_ne_bytes())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_flattened();
|
||||||
|
constants.push((vk::ShaderStageFlags::VERTEX, 32, screen_res));
|
||||||
|
|
||||||
|
let base_color: Vec<u8> = (Vec::<f32>::from([0.0, 1.0, 1.0, 1.0]))
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.to_ne_bytes())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_flattened();
|
||||||
|
constants.push((vk::ShaderStageFlags::FRAGMENT, 48, base_color));
|
||||||
|
|
||||||
|
constants
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_verticies(&self) -> u32 {
|
||||||
|
self.num_vert as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ChunkRender {
|
||||||
|
mesh_buf: vk::Buffer,
|
||||||
|
num_vert: usize,
|
||||||
|
pipeline: vk::Pipeline,
|
||||||
|
pipe_layout: vk::PipelineLayout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderCtx {
|
||||||
|
fn create_chunk(&self, pass: vk::RenderPass, chunk: &Chunk) -> ChunkRender {
|
||||||
|
let mut mesh = Mesh::default();
|
||||||
|
chunk.mesh(&mut mesh);
|
||||||
|
let num_vert = mesh.num_vert();
|
||||||
|
let buf = mesh.to_buffer();
|
||||||
|
|
||||||
|
let mesh_mem = self.mem_alloc(
|
||||||
|
MemType::HostVisibile,
|
||||||
|
(buf.len() * size_of::<PosNorm>()) as u64,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mesh_buf = self.alloc_buf(
|
||||||
|
mesh_mem,
|
||||||
|
(buf.len() * size_of::<PosNorm>()) as u64,
|
||||||
|
vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::STORAGE_BUFFER,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mesh_mem = self.buf_to_ptr(mesh_mem, mesh_buf);
|
||||||
|
unsafe {
|
||||||
|
std::ptr::copy(buf.as_ptr(), mesh_mem as *mut PosNorm, buf.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
let pipe_layout = setup_pipe_layout(self);
|
||||||
|
let pipeline = setup_pipeline(self, &pass, pipe_layout);
|
||||||
|
|
||||||
|
ChunkRender {
|
||||||
|
mesh_buf,
|
||||||
|
num_vert,
|
||||||
|
pipeline,
|
||||||
|
pipe_layout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game<LoadingWorld> {
|
||||||
|
/// Create a cube to be rendered in world, this can then be
|
||||||
|
/// added using [`Game<LoadingWorld>::add_component`]
|
||||||
|
pub fn create_chunk(&self, chunk: &Chunk) -> ChunkRender {
|
||||||
|
let Self {
|
||||||
|
state: LoadingWorld { ctx, pass, .. },
|
||||||
|
} = self;
|
||||||
|
ctx.create_chunk(*pass, chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_chunk_shaders(ctx: &RenderCtx) -> (vk::ShaderModule, vk::ShaderModule) {
|
||||||
|
let shader_vert_shader = ctx.shader_mod_from_file(
|
||||||
|
"shaders/chunk_vert.spv",
|
||||||
|
vk::ShaderModuleCreateFlags::empty(),
|
||||||
|
);
|
||||||
|
let shader_frag_shader = ctx.shader_mod_from_file(
|
||||||
|
"shaders/chunk_frag.spv",
|
||||||
|
vk::ShaderModuleCreateFlags::empty(),
|
||||||
|
);
|
||||||
|
|
||||||
|
(shader_vert_shader, shader_frag_shader)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_desc_layout(ctx: &RenderCtx) -> vk::DescriptorSetLayout {
|
||||||
|
let storage_binding = vk::DescriptorSetLayoutBinding::default()
|
||||||
|
.binding(0)
|
||||||
|
.descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
|
||||||
|
.descriptor_count(1)
|
||||||
|
.stage_flags(vk::ShaderStageFlags::VERTEX);
|
||||||
|
let layouts = [storage_binding];
|
||||||
|
|
||||||
|
let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&layouts);
|
||||||
|
let layout = unsafe {
|
||||||
|
ctx.dev
|
||||||
|
.create_descriptor_set_layout(&layout_info, None)
|
||||||
|
.expect("Failed to create descriptor set layout")
|
||||||
|
};
|
||||||
|
layout
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_pipe_layout(ctx: &RenderCtx) -> vk::PipelineLayout {
|
||||||
|
let layout = setup_desc_layout(ctx);
|
||||||
|
let push_range: [vk::PushConstantRange; 2] = [
|
||||||
|
vk::PushConstantRange::default()
|
||||||
|
.stage_flags(vk::ShaderStageFlags::VERTEX)
|
||||||
|
.offset(0)
|
||||||
|
.size(48), // vec4 camera_orig, camera_rot; uvec2 screen_res
|
||||||
|
vk::PushConstantRange::default()
|
||||||
|
.stage_flags(vk::ShaderStageFlags::FRAGMENT)
|
||||||
|
.offset(48)
|
||||||
|
.size(16), // vec4 base_color
|
||||||
|
];
|
||||||
|
|
||||||
|
let layouts = &[layout];
|
||||||
|
|
||||||
|
let pipe_layout = vk::PipelineLayoutCreateInfo::default()
|
||||||
|
.set_layouts(layouts.as_ref())
|
||||||
|
.push_constant_ranges(&push_range);
|
||||||
|
let pipe_layout = unsafe {
|
||||||
|
ctx.dev
|
||||||
|
.create_pipeline_layout(&pipe_layout, None)
|
||||||
|
.expect("Failed to create pipeline layout")
|
||||||
|
};
|
||||||
|
pipe_layout
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_pipeline(
|
||||||
|
ctx: &RenderCtx,
|
||||||
|
pass: &vk::RenderPass,
|
||||||
|
layout: vk::PipelineLayout,
|
||||||
|
) -> vk::Pipeline {
|
||||||
|
let (vert_shader, frag_shader) = load_chunk_shaders(ctx);
|
||||||
|
let shader_stages = ctx.setup_simple_shader_stage(vert_shader, frag_shader);
|
||||||
|
let vert_input = vk::PipelineVertexInputStateCreateInfo::default();
|
||||||
|
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
|
||||||
|
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
|
||||||
|
let rasterization = vk::PipelineRasterizationStateCreateInfo::default()
|
||||||
|
.polygon_mode(vk::PolygonMode::FILL)
|
||||||
|
.cull_mode(vk::CullModeFlags::NONE)
|
||||||
|
.front_face(vk::FrontFace::CLOCKWISE)
|
||||||
|
.line_width(1.0);
|
||||||
|
let multisample = vk::PipelineMultisampleStateCreateInfo::default()
|
||||||
|
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
|
||||||
|
let depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default()
|
||||||
|
.depth_test_enable(true)
|
||||||
|
.depth_write_enable(true)
|
||||||
|
.depth_compare_op(vk::CompareOp::LESS)
|
||||||
|
.depth_bounds_test_enable(true)
|
||||||
|
.stencil_test_enable(false)
|
||||||
|
.min_depth_bounds(0.0)
|
||||||
|
.max_depth_bounds(1.0);
|
||||||
|
|
||||||
|
let blend = vk::PipelineColorBlendAttachmentState::default()
|
||||||
|
.src_color_blend_factor(vk::BlendFactor::SRC_COLOR)
|
||||||
|
.dst_color_blend_factor(vk::BlendFactor::SRC_COLOR)
|
||||||
|
.color_blend_op(vk::BlendOp::ADD)
|
||||||
|
.src_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
|
||||||
|
.dst_alpha_blend_factor(vk::BlendFactor::SRC_COLOR)
|
||||||
|
.alpha_blend_op(vk::BlendOp::ADD)
|
||||||
|
.color_write_mask(
|
||||||
|
vk::ColorComponentFlags::R
|
||||||
|
| vk::ColorComponentFlags::G
|
||||||
|
| vk::ColorComponentFlags::B
|
||||||
|
| vk::ColorComponentFlags::A,
|
||||||
|
);
|
||||||
|
|
||||||
|
let blend_attachments = [blend];
|
||||||
|
|
||||||
|
let color_blend = vk::PipelineColorBlendStateCreateInfo::default()
|
||||||
|
.attachments(blend_attachments.as_ref())
|
||||||
|
.logic_op_enable(false)
|
||||||
|
.logic_op(vk::LogicOp::COPY)
|
||||||
|
.blend_constants([1.0, 1.0, 1.0, 1.0]);
|
||||||
|
|
||||||
|
let dynamic = vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&[
|
||||||
|
vk::DynamicState::VIEWPORT_WITH_COUNT,
|
||||||
|
vk::DynamicState::SCISSOR_WITH_COUNT,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let pipe_info = vk::GraphicsPipelineCreateInfo::default()
|
||||||
|
.stages(&shader_stages)
|
||||||
|
.vertex_input_state(&vert_input)
|
||||||
|
.input_assembly_state(&input_assembly)
|
||||||
|
.rasterization_state(&rasterization)
|
||||||
|
.multisample_state(&multisample)
|
||||||
|
.depth_stencil_state(&depth_stencil)
|
||||||
|
.color_blend_state(&color_blend)
|
||||||
|
.layout(layout)
|
||||||
|
.dynamic_state(&dynamic)
|
||||||
|
.render_pass(*pass)
|
||||||
|
.subpass(0);
|
||||||
|
|
||||||
|
let pipe = unsafe {
|
||||||
|
ctx.dev
|
||||||
|
.create_graphics_pipelines(vk::PipelineCache::null(), &[pipe_info], None)
|
||||||
|
.expect("Failed to create graphics pipeline")
|
||||||
|
.remove(0)
|
||||||
|
};
|
||||||
|
println!("Created pipeline");
|
||||||
|
pipe
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
use std::iter::repeat;
|
||||||
|
|
||||||
|
use crate::{game::chunk::Block, vec3, vector::Vector3};
|
||||||
|
|
||||||
|
use super::Mesh;
|
||||||
|
|
||||||
|
const TOP_POSITIONS: [Vector3<f32>; 6] = [
|
||||||
|
vec3!(0.0, 1.0, 0.0),
|
||||||
|
vec3!(1.0, 1.0, 0.0),
|
||||||
|
vec3!(0.0, 1.0, 1.0),
|
||||||
|
vec3!(1.0, 1.0, 1.0),
|
||||||
|
vec3!(1.0, 1.0, 0.0),
|
||||||
|
vec3!(0.0, 1.0, 1.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
const TOP_NORMAL: Vector3<f32> = vec3!(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
const BOTTOM_POSITIONS: [Vector3<f32>; 6] = [
|
||||||
|
vec3!(0.0, 0.0, 0.0),
|
||||||
|
vec3!(1.0, 0.0, 0.0),
|
||||||
|
vec3!(0.0, 0.0, 1.0),
|
||||||
|
vec3!(1.0, 0.0, 1.0),
|
||||||
|
vec3!(1.0, 0.0, 0.0),
|
||||||
|
vec3!(0.0, 0.0, 1.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
const BOTTOM_NORMAL: Vector3<f32> = vec3!(0.0, -1.0, 0.0);
|
||||||
|
|
||||||
|
const NORTH_POSITIONS: [Vector3<f32>; 6] = [
|
||||||
|
vec3!(1.0, 0.0, 0.0),
|
||||||
|
vec3!(1.0, 1.0, 0.0),
|
||||||
|
vec3!(1.0, 0.0, 1.0),
|
||||||
|
vec3!(1.0, 1.0, 1.0),
|
||||||
|
vec3!(1.0, 1.0, 0.0),
|
||||||
|
vec3!(1.0, 0.0, 1.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
const NORTH_NORMAL: Vector3<f32> = vec3!(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
const SOUTH_POSITIONS: [Vector3<f32>; 6] = [
|
||||||
|
vec3!(0.0, 0.0, 0.0),
|
||||||
|
vec3!(0.0, 1.0, 0.0),
|
||||||
|
vec3!(0.0, 0.0, 1.0),
|
||||||
|
vec3!(0.0, 1.0, 1.0),
|
||||||
|
vec3!(0.0, 1.0, 0.0),
|
||||||
|
vec3!(0.0, 0.0, 1.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
const SOUTH_NORMAL: Vector3<f32> = vec3!(-1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
const EAST_POSITIONS: [Vector3<f32>; 6] = [
|
||||||
|
vec3!(0.0, 0.0, 1.0),
|
||||||
|
vec3!(1.0, 0.0, 1.0),
|
||||||
|
vec3!(0.0, 1.0, 1.0),
|
||||||
|
vec3!(1.0, 1.0, 1.0),
|
||||||
|
vec3!(1.0, 0.0, 1.0),
|
||||||
|
vec3!(0.0, 1.0, 1.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
const EAST_NORMAL: Vector3<f32> = vec3!(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
const WEST_POSITIONS: [Vector3<f32>; 6] = [
|
||||||
|
vec3!(0.0, 0.0, 0.0),
|
||||||
|
vec3!(1.0, 0.0, 0.0),
|
||||||
|
vec3!(0.0, 1.0, 0.0),
|
||||||
|
vec3!(1.0, 1.0, 0.0),
|
||||||
|
vec3!(1.0, 0.0, 0.0),
|
||||||
|
vec3!(0.0, 1.0, 0.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
const WEST_NORMAL: Vector3<f32> = vec3!(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
const POSITIONS: [&'static [Vector3<f32>; 6]; 6] = [
|
||||||
|
&TOP_POSITIONS,
|
||||||
|
&BOTTOM_POSITIONS,
|
||||||
|
&NORTH_POSITIONS,
|
||||||
|
&SOUTH_POSITIONS,
|
||||||
|
&EAST_POSITIONS,
|
||||||
|
&WEST_POSITIONS,
|
||||||
|
];
|
||||||
|
|
||||||
|
const NORMALS: [&'static Vector3<f32>; 6] = [
|
||||||
|
&TOP_NORMAL,
|
||||||
|
&BOTTOM_NORMAL,
|
||||||
|
&NORTH_NORMAL,
|
||||||
|
&SOUTH_NORMAL,
|
||||||
|
&EAST_NORMAL,
|
||||||
|
&WEST_NORMAL,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn mesh_block(mesh: &mut Mesh, block: &Block, pos: Vector3<i32>, sides: [bool; 6]) {
|
||||||
|
let pos = Into::<Vector3<f32>>::into(pos);
|
||||||
|
mesh.positions.extend(
|
||||||
|
POSITIONS
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(sides)
|
||||||
|
.filter_map(|(s, e)| e.then(|| s.iter().map(|p| *p + pos)))
|
||||||
|
.flatten(),
|
||||||
|
);
|
||||||
|
mesh.normals.extend(
|
||||||
|
NORMALS
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.zip(sides)
|
||||||
|
.filter_map(|(s, e)| e.then(|| repeat(s).take(6)))
|
||||||
|
.flatten(),
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
use crate::{game::chunk::Chunk, vec3, vector::Vector3};
|
||||||
|
|
||||||
|
use super::{Mesh, block_mesher::mesh_block};
|
||||||
|
|
||||||
|
const NEIGHBOURS: [Vector3<i32>; 6] = [
|
||||||
|
vec3!(0, 1, 0),
|
||||||
|
vec3!(0, -1, 0),
|
||||||
|
vec3!(1, 0, 0),
|
||||||
|
vec3!(-1, 0, 0),
|
||||||
|
vec3!(0, 0, 1),
|
||||||
|
vec3!(0, 0, -1),
|
||||||
|
];
|
||||||
|
|
||||||
|
impl Chunk {
|
||||||
|
pub fn mesh(&self, mesh: &mut Mesh) {
|
||||||
|
for (block, b_pos) in self.blocks().filter(|(b, _)| !b.is_transparent()) {
|
||||||
|
let mut sides = [false; 6];
|
||||||
|
sides
|
||||||
|
.iter_mut()
|
||||||
|
.zip(NEIGHBOURS.iter().copied())
|
||||||
|
.for_each(|(f, n)| {
|
||||||
|
*f = self
|
||||||
|
.get_block(b_pos + n)
|
||||||
|
.map(|b| b.is_transparent())
|
||||||
|
.unwrap_or(true)
|
||||||
|
});
|
||||||
|
mesh_block(mesh, block, b_pos + (self.chunk_coord * 16), sides);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
use crate::vector::Vector3;
|
||||||
|
|
||||||
|
mod block_mesher;
|
||||||
|
mod chunk_mesher;
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct Mesh {
|
||||||
|
positions: Vec<Vector3<f32>>,
|
||||||
|
normals: Vec<Vector3<f32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PosNorm {
|
||||||
|
pos: [f32; 4],
|
||||||
|
norm: [f32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PosNorm {
|
||||||
|
fn new(pos: Vector3<f32>, norm: Vector3<f32>) -> Self {
|
||||||
|
Self {
|
||||||
|
pos: [pos.x, pos.y, pos.z, 0.0],
|
||||||
|
norm: [norm.x, norm.y, norm.z, 0.0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mesh {
|
||||||
|
pub fn to_buffer(self) -> Vec<PosNorm> {
|
||||||
|
let Self { positions, normals } = self;
|
||||||
|
positions
|
||||||
|
.into_iter()
|
||||||
|
.zip(normals.into_iter())
|
||||||
|
.map(|(p, n)| PosNorm::new(p, n))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_vert(&self) -> usize {
|
||||||
|
self.positions.len()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
use std::ops::{Add, Mul, Sub};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! vec3 {
|
||||||
|
($x:expr, $y:expr, $z:expr) => {
|
||||||
|
$crate::vector::Vector3 {
|
||||||
|
x: $x,
|
||||||
|
y: $y,
|
||||||
|
z: $z,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Vector3<S> {
|
||||||
|
pub x: S,
|
||||||
|
pub y: S,
|
||||||
|
pub z: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Vector3<f32>> for Vector3<i32> {
|
||||||
|
fn into(self) -> Vector3<f32> {
|
||||||
|
Vector3 {
|
||||||
|
x: self.x as f32,
|
||||||
|
y: self.y as f32,
|
||||||
|
z: self.z as f32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Clone> Clone for Vector3<S> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.x.clone(),
|
||||||
|
y: self.y.clone(),
|
||||||
|
z: self.z.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Copy> Copy for Vector3<S> {}
|
||||||
|
|
||||||
|
impl<S: Add<Output = S>> Add for Vector3<S> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
z: self.z + rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Sub<Output = S>> Sub for Vector3<S> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
z: self.z - rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Mul<Output = S>> Mul for Vector3<S> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs.x,
|
||||||
|
y: self.y * rhs.y,
|
||||||
|
z: self.z * rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Mul<Output = S> + Copy> Mul<S> for Vector3<S> {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: S) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs,
|
||||||
|
y: self.y * rhs,
|
||||||
|
z: self.z * rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue