diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..98c34ff
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/shaders/line.vert b/shaders/line.vert
index 0d82f83..d0d7709 100644
--- a/shaders/line.vert
+++ b/shaders/line.vert
@@ -2,6 +2,12 @@
layout(location = 0) in vec3 position;
+layout(push_constant) uniform LinePushConstants {
+ mat4 model;
+ mat4 view;
+ mat4 projection;
+} push;
+
void main() {
- gl_Position = vec4(position, 1.0);
+ gl_Position = push.projection * push.view * push.model * vec4(position, 1.0);
}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 4fbe008..05890ad 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,7 +4,6 @@ use std::iter::FromIterator;
use cgmath::{Matrix4, Rad, Point3, Vector3, Deg};
mod vulkan;
-use vulkan::vs::ty::PushConstants;
const PRINT_KEYBOARD_INPUT: bool = false;
@@ -24,7 +23,7 @@ impl Game for TestGame {
let mut proj = cgmath::perspective(
Rad::from(Deg(45.0)),
- game_data.aspect_ratio,
+ game_data.dimensions[0] as f32 / game_data.dimensions[1] as f32,
0.1,
10.0
);
@@ -34,9 +33,11 @@ impl Game for TestGame {
game_data.push_constants.model = model.into();
game_data.push_constants.view = view.into();
game_data.push_constants.projection = proj.into();
+ game_data.line_push_constants.view = view.into();
+ game_data.line_push_constants.projection = proj.into();
}
- fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event) -> bool {
+ fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event) {
match event {
Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input }, .. } => {
if PRINT_KEYBOARD_INPUT {
@@ -61,7 +62,6 @@ impl Game for TestGame {
}
_ => {}
}
- return false;
}
}
@@ -69,10 +69,13 @@ fn main() {
let mut game = TestGame {};
vulkan::init(
"models/box.obj",
- vec![
- LinePoint { position: [-0.9, 1., 0.] },
- LinePoint { position: [0.9, 0., 0.] },
- ],
+ (-10..10)
+ .flat_map(|it| vec![
+ LinePoint { position: [it as f32, -10., 0.] },
+ LinePoint { position: [it as f32, 10., 0.] },
+ LinePoint { position: [-10., it as f32, 0.] },
+ LinePoint { position: [10., it as f32, 0.] },
+ ]).collect(),
&mut game
);
}
\ No newline at end of file
diff --git a/src/vulkan.rs b/src/vulkan.rs
index d833820..4adf066 100644
--- a/src/vulkan.rs
+++ b/src/vulkan.rs
@@ -2,7 +2,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState};
use vulkano::device::{Device, DeviceExtensions};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
-use vulkano::image::{SwapchainImage, AttachmentImage};
+use vulkano::image::{SwapchainImage, AttachmentImage, ImageUsage};
use vulkano::instance::{Instance, PhysicalDevice, ApplicationInfo, Version, InstanceExtensions};
use vulkano::pipeline::{GraphicsPipeline};
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule};
@@ -13,7 +13,8 @@ use vulkano::sync::{GpuFuture, FlushError};
use vulkano::sync;
use vulkano::pipeline::vertex::{SingleBufferDefinition};
use vulkano::descriptor::PipelineLayoutAbstract;
-use vulkano::format::Format;
+use vulkano::format::{Format, ClearValue};
+use vulkano::instance::debug::{DebugCallback, MessageTypes};
use vulkano_win::VkSurfaceBuild;
@@ -30,10 +31,11 @@ use shade_runner;
use shade_runner::{CompiledShaders, Entry};
use shaderc;
-use crate::PushConstants;
-use vulkano::instance::debug::{DebugCallback, MessageTypes};
+use vs::ty::PushConstants;
+use line_vs::ty::LinePushConstants;
use tobj::{load_obj};
+use vulkano::pipeline::depth_stencil::DepthStencil;
const VALIDATION_LAYERS: &[&str] = &[
"VK_LAYER_LUNARG_standard_validation"
@@ -62,20 +64,19 @@ pub trait Game {
fn update(self: &mut Self, game_data: &mut GameData);
/// Returns true if event should be ignored by the vulkan handler
- fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event) -> bool;
+ fn on_window_event(self: &mut Self, game_data: &mut GameData, event: &Event);
}
pub struct GameData {
pub start_time: SystemTime,
pub line_vertices: Vec,
pub push_constants: PushConstants,
+ pub line_push_constants: LinePushConstants,
pub recreate_pipeline: bool,
- pub aspect_ratio: f32,
+ pub dimensions: [u32; 2],
pub shutdown: bool,
}
-
-
pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game) {
let mut data = GameData {
push_constants: PushConstants {
@@ -85,11 +86,16 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
view: Matrix4::identity().into(),
projection: Matrix4::identity().into(),
},
+ line_push_constants: LinePushConstants {
+ model: Matrix4::identity().into(),
+ view: Matrix4::identity().into(),
+ projection: Matrix4::identity().into(),
+ },
start_time: SystemTime::now(),
recreate_pipeline: false,
- aspect_ratio: 1.0,
shutdown: false,
line_vertices,
+ dimensions: [0, 0]
};
if ENABLE_VALIDATION_LAYERS {
@@ -190,7 +196,7 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
// These drivers will allow anything but the only sensible value is the window dimensions.
//
// Because for both of these cases, the swapchain needs to be the window dimensions, we just use that.
- let initial_dimensions = if let Some(dimensions) = window.get_inner_size() {
+ data.dimensions = if let Some(dimensions) = window.get_inner_size() {
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
[dimensions.0, dimensions.1]
} else {
@@ -198,7 +204,7 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
};
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
- initial_dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
+ data.dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
PresentMode::Fifo, true, None).unwrap()
};
@@ -221,6 +227,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
store: DontCare,
format: Format::D16Unorm,
samples: 1,
+ initial_layout: ImageLayout::Undefined,
+ final_layout: ImageLayout::DepthStencilAttachmentOptimal,
}
},
pass: {
@@ -231,8 +239,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
- let mut pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap();
- let line_pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/line.vert", "shaders/line.frag", true).unwrap();
+ let mut pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap();
+ let line_pipeline = create_pipeline(device.clone(), sub_pass.clone(), "shaders/line.vert", "shaders/line.frag", true ).unwrap();
// Dynamic viewports allow us to recreate just the viewport when the window is resized
// Otherwise we would have to recreate the whole pipeline.
@@ -240,7 +248,7 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
// The render pass we created above only describes the layout of our framebuffers. Before we
// can draw we also need to create the actual framebuffers.
- let mut framebuffers = window_size_dependent_setup(device.clone(), &images, render_pass.clone(), &mut dynamic_state, &mut data.aspect_ratio);
+ let mut framebuffers = window_size_dependent_setup(device.clone(), &images, render_pass.clone(), &mut dynamic_state);
let mut recreate_swapchain = false;
@@ -278,7 +286,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
swapchain = new_swapchain;
// Because framebuffers contains an Arc on the old swapchain, we need to
// recreate framebuffers as well.
- framebuffers = window_size_dependent_setup(device.clone(), &new_images, render_pass.clone(), &mut dynamic_state, &mut data.aspect_ratio);
+ framebuffers = window_size_dependent_setup(device.clone(), &new_images, render_pass.clone(), &mut dynamic_state);
+ data.dimensions = images[0].dimensions();
recreate_swapchain = false;
}
@@ -311,22 +320,15 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
game.update(&mut data);
- // Specify the color to clear the framebuffer with i.e. blue
- let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into(), 1f32.into());
-
let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
// Before we can draw, we have to *enter a render pass*. There are two methods to do
// this: `draw_inline` and `draw_secondary`. The latter is a bit more advanced and is
// not covered here.
- //
- // The third parameter builds the list of values to clear the attachments with. The API
- // is similar to the list of attachments when building the framebuffers, except that
- // only the attachments that use `load: Clear` appear in the list.
- .begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap()
+ .begin_render_pass(framebuffers[image_num].clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into(), ClearValue::Depth(1.0)]).unwrap()
// We are now inside the first subpass of the render pass. We add a draw command.
.draw_indexed(pipeline.clone(), &dynamic_state, mesh_vertex_buffer.clone(), mesh_index_buffer.clone(), (), data.push_constants.clone()).unwrap()
- .draw(line_pipeline.clone(), &dynamic_state, line_vertex_buffer.clone(), (), ()).unwrap()
+ .draw(line_pipeline.clone(), &dynamic_state, line_vertex_buffer.clone(), (), data.line_push_constants.clone()).unwrap()
// We leave the render pass by calling `draw_end`. Note that if we had multiple
// subpasses we could have called `next_inline` (or `next_secondary`) to jump to the
@@ -363,12 +365,11 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
// wait would happen. Blocking may be the desired behavior, but if you don't want to
// block you should spawn a separate thread dedicated to submissions.
events_loop.poll_events(|ev| {
- if !game.on_window_event(&mut data, &ev) {
- match ev {
- Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => data.shutdown = true,
- Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
- _ => {}
- }
+ game.on_window_event(&mut data, &ev);
+ match ev {
+ Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => data.shutdown = true,
+ Event::WindowEvent { event: WindowEvent::Resized(_), .. } => recreate_swapchain = true,
+ _ => {}
}
});
if data.shutdown { return; }
@@ -376,9 +377,8 @@ pub fn init(mesh_path: &str, line_vertices: Vec, game: &mut dyn Game)
}
/// This method is called once during initialization, then again whenever the window is resized
-fn window_size_dependent_setup(device: Arc, images: &[Arc>], render_pass: Arc, dynamic_state: &mut DynamicState, aspect_ratio: &mut f32) -> Vec> {
+fn window_size_dependent_setup(device: Arc, images: &[Arc>], render_pass: Arc, dynamic_state: &mut DynamicState) -> Vec> {
let dimensions = images[0].dimensions();
- *aspect_ratio = dimensions[0] as f32 / dimensions[1] as f32;
let viewport = Viewport {
origin: [0.0, 0.0],
@@ -387,12 +387,12 @@ fn window_size_dependent_setup(device: Arc, images: &[Arc
}).collect::>()
@@ -405,6 +405,13 @@ pub mod vs {
}
}
+pub mod line_vs {
+ vulkano_shaders::shader!{
+ ty: "vertex",
+ path: "shaders/line.vert"
+ }
+}
+
pub mod fs {
vulkano_shaders::shader! {
ty: "fragment",
@@ -412,6 +419,13 @@ pub mod fs {
}
}
+pub mod line_fs {
+ vulkano_shaders::shader! {
+ ty: "fragment",
+ path: "shaders/line.frag"
+ }
+}
+
fn create_pipeline(device: Arc, sub_pass: Subpass>, vertex_shader_path: &str, fragment_shader_path: &str, is_line: bool) -> Option, Box, Arc>>> {
if let Some((shader, shader_data)) = read_shader(vertex_shader_path, fragment_shader_path) {
let vertex_shader_entry;
@@ -443,6 +457,7 @@ fn create_pipeline(
.vertex_shader(vertex_shader_entry.clone(), ())
.line_list()
.viewports_dynamic_scissors_irrelevant(1)
+ .depth_stencil(DepthStencil::simple_depth_test())
.fragment_shader(fragment_shader_entry.clone(), ())
.render_pass(sub_pass.clone())
.build(device.clone())