forked from itycodes/MineClone
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
11 KiB
402 lines
11 KiB
use std::collections::HashMap;
|
|
|
|
use ash::vk;
|
|
|
|
use crate::{Game, LoadingWorld, RenderCtx, render::MemType};
|
|
|
|
use super::loading_world::WorldComponent;
|
|
|
|
pub struct Cube {
|
|
mesh_buf: vk::Buffer,
|
|
pipeline: vk::Pipeline,
|
|
pipe_layout: vk::PipelineLayout,
|
|
}
|
|
|
|
const MESH_SIZE: u64 = 36 * 2 * 4 * 4;
|
|
|
|
#[rustfmt::skip]
|
|
const POSITIONS: [f32; 36 * 2 * 4] = [
|
|
// BOTTOM
|
|
-0.5, 0.5, 1.0, 1.0,
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
0.5, 0.5, 2.0, 1.0,
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
-0.5, 0.5, 2.0, 1.0,
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
0.5, 0.5, 1.0, 1.0,
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
0.5, 0.5, 2.0, 1.0,
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
-0.5, 0.5, 1.0, 1.0,
|
|
0.0, 1.0, 0.0, 0.0,
|
|
|
|
// TOP
|
|
0.5, -0.5, 2.0, 1.0,
|
|
0.0, -1.0, 0.0, 0.0,
|
|
|
|
-0.5, -0.5, 1.0, 1.0,
|
|
0.0, -1.0, 0.0, 0.0,
|
|
|
|
-0.5, -0.5, 2.0, 1.0,
|
|
0.0, -1.0, 0.0, 0.0,
|
|
|
|
0.5, -0.5, 2.0, 1.0,
|
|
0.0, -1.0, 0.0, 0.0,
|
|
|
|
0.5, -0.5, 1.0, 1.0,
|
|
0.0, -1.0, 0.0, 0.0,
|
|
|
|
-0.5, -0.5, 1.0, 1.0,
|
|
0.0, -1.0, 0.0, 0.0,
|
|
|
|
// FRONT
|
|
-0.5, -0.5, 1.0, 1.0,
|
|
0.0, 0.0, -1.0, 0.0,
|
|
|
|
0.5, 0.5, 1.0, 1.0,
|
|
0.0, 0.0, -1.0, 0.0,
|
|
|
|
-0.5, 0.5, 1.0, 1.0,
|
|
0.0, 0.0, -1.0, 0.0,
|
|
|
|
0.5, -0.5, 1.0, 1.0,
|
|
0.0, 0.0, -1.0, 0.0,
|
|
|
|
0.5, 0.5, 1.0, 1.0,
|
|
0.0, 0.0, -1.0, 0.0,
|
|
|
|
-0.5, -0.5, 1.0, 1.0,
|
|
0.0, 0.0, -1.0, 0.0,
|
|
|
|
// BACK
|
|
0.5, 0.5, 2.0, 1.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
-0.5, -0.5, 2.0, 1.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
-0.5, 0.5, 2.0, 1.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
0.5, 0.5, 2.0, 1.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
0.5, -0.5, 2.0, 1.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
-0.5, -0.5, 2.0, 1.0,
|
|
0.0, 0.0, 1.0, 0.0,
|
|
|
|
// LEFT
|
|
-0.5, -0.5, 1.0, 1.0,
|
|
-1.0, 0.0, 0.0, 0.0,
|
|
|
|
-0.5, 0.5, 2.0, 1.0,
|
|
-1.0, 0.0, 0.0, 0.0,
|
|
|
|
-0.5, -0.5, 2.0, 1.0,
|
|
-1.0, 0.0, 0.0, 0.0,
|
|
|
|
-0.5, 0.5, 1.0, 1.0,
|
|
-1.0, 0.0, 0.0, 0.0,
|
|
|
|
-0.5, 0.5, 2.0, 1.0,
|
|
-1.0, 0.0, 0.0, 0.0,
|
|
|
|
-0.5, -0.5, 1.0, 1.0,
|
|
-1.0, 0.0, 0.0, 0.0,
|
|
|
|
// RIGHT
|
|
0.5, 0.5, 2.0, 1.0,
|
|
1.0, 0.0, 0.0, 0.0,
|
|
|
|
0.5, -0.5, 1.0, 1.0,
|
|
1.0, 0.0, 0.0, 0.0,
|
|
|
|
0.5, -0.5, 2.0, 1.0,
|
|
1.0, 0.0, 0.0, 0.0,
|
|
|
|
0.5, 0.5, 2.0, 1.0,
|
|
1.0, 0.0, 0.0, 0.0,
|
|
|
|
0.5, 0.5, 1.0, 1.0,
|
|
1.0, 0.0, 0.0, 0.0,
|
|
|
|
0.5, -0.5, 1.0, 1.0,
|
|
1.0, 0.0, 0.0, 0.0,
|
|
];
|
|
|
|
impl WorldComponent for Cube {
|
|
fn descriptors(&self) -> std::collections::HashMap<vk::DescriptorType, u32> {
|
|
let mut map = HashMap::new();
|
|
map.insert(vk::DescriptorType::COMBINED_IMAGE_SAMPLER, 1);
|
|
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);
|
|
|
|
let img_info = vk::DescriptorImageInfo::default()
|
|
.image_layout(vk::ImageLayout::GENERAL)
|
|
.image_view(skybox.0)
|
|
.sampler(skybox.1);
|
|
let img_infos = &[img_info];
|
|
let img_desc = vk::WriteDescriptorSet::default()
|
|
.dst_set(desc_set)
|
|
.dst_binding(1)
|
|
.dst_array_element(0)
|
|
.descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
|
.image_info(img_infos);
|
|
|
|
unsafe {
|
|
ctx.dev.update_descriptor_sets(&[buf_desc, img_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 {
|
|
36
|
|
}
|
|
}
|
|
|
|
impl RenderCtx {
|
|
fn create_cube(&self, pass: vk::RenderPass) -> Cube {
|
|
let mesh_mem = self.mem_alloc(MemType::HostVisibile, MESH_SIZE);
|
|
|
|
let mesh_buf = self.alloc_buf(
|
|
mesh_mem,
|
|
MESH_SIZE,
|
|
vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::STORAGE_BUFFER,
|
|
);
|
|
|
|
let mesh_mem = self.buf_to_ptr(mesh_mem, mesh_buf);
|
|
unsafe {
|
|
std::ptr::copy(POSITIONS.as_ptr(), mesh_mem as *mut f32, POSITIONS.len());
|
|
}
|
|
|
|
let pipe_layout = setup_pipe_layout(self);
|
|
let pipeline = setup_pipeline(self, &pass, pipe_layout);
|
|
|
|
Cube {
|
|
mesh_buf,
|
|
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_cube(&self) -> Cube {
|
|
let Self {
|
|
state: LoadingWorld { ctx, pass, .. },
|
|
} = self;
|
|
ctx.create_cube(*pass)
|
|
}
|
|
}
|
|
|
|
fn load_cube_shaders(ctx: &RenderCtx) -> (vk::ShaderModule, vk::ShaderModule) {
|
|
let shader_vert_shader = ctx.shader_mod_from_file(
|
|
"shaders/cube_vert.spv",
|
|
vk::ShaderModuleCreateFlags::empty(),
|
|
);
|
|
let shader_frag_shader = ctx.shader_mod_from_file(
|
|
"shaders/cube_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 image_binding = vk::DescriptorSetLayoutBinding::default()
|
|
.binding(1)
|
|
.descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
|
.descriptor_count(1)
|
|
.stage_flags(vk::ShaderStageFlags::FRAGMENT);
|
|
let layouts = [storage_binding, image_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_cube_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::BACK)
|
|
.front_face(vk::FrontFace::COUNTER_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
|
|
}
|