Fix and module update
This commit is contained in:
24
Cargo.toml
24
Cargo.toml
@@ -5,16 +5,14 @@ authors = ["Till <asuro@posteo.de>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vulkano-shaders = "0.13"
|
vulkano-shaders = "0.19.0"
|
||||||
vulkano = "0.13"
|
vulkano = "0.19.0"
|
||||||
vulkano-win = "0.13"
|
vulkano-win = "0.19.0"
|
||||||
shade_runner = "0.1.2"
|
cgmath = "0.17.0"
|
||||||
shaderc = "0.5.0"
|
winit = "0.22.2"
|
||||||
cgmath = "0.17"
|
image = "0.23.6"
|
||||||
winit = "0.19"
|
serde = "1.0.114"
|
||||||
image = "0.22.0"
|
serde_derive = "1.0.114"
|
||||||
serde = "1.0.97"
|
toml = "0.5.6"
|
||||||
serde_derive = "1.0.97"
|
gilrs = "0.7.4"
|
||||||
toml = "0.5.1"
|
gltf = "0.15.2"
|
||||||
gilrs = "0.7.1"
|
|
||||||
gltf = "0.13.0"
|
|
||||||
73
src/input.rs
73
src/input.rs
@@ -1,4 +1,6 @@
|
|||||||
use winit::{ScanCode, ModifiersState, MouseButton, ElementState, MouseScrollDelta, Event, WindowEvent, DeviceEvent};
|
#![allow(deprecated)]
|
||||||
|
|
||||||
|
use winit::event::{ScanCode, MouseButton, ElementState, MouseScrollDelta, Event, WindowEvent, DeviceEvent, ModifiersState};
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@@ -81,6 +83,25 @@ pub struct InputState {
|
|||||||
controller_input: Gilrs,
|
controller_input: Gilrs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
|
pub struct KeyboardModifierState {
|
||||||
|
shift: bool,
|
||||||
|
ctrl: bool,
|
||||||
|
alt: bool,
|
||||||
|
logo: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyboardModifierState {
|
||||||
|
pub fn from_deprecated_state(old_state: &ModifiersState) -> KeyboardModifierState {
|
||||||
|
KeyboardModifierState {
|
||||||
|
shift: old_state.shift(),
|
||||||
|
ctrl: old_state.ctrl(),
|
||||||
|
alt: old_state.alt(),
|
||||||
|
logo: old_state.logo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl InputState {
|
impl InputState {
|
||||||
pub fn new(toml_path: &str, log_config: LogConfig) -> InputState {
|
pub fn new(toml_path: &str, log_config: LogConfig) -> InputState {
|
||||||
let config: InputConfig = toml::from_slice(&fs::read(toml_path).expect("Failed to read input config!")).expect("Failed to parse input config!");
|
let config: InputConfig = toml::from_slice(&fs::read(toml_path).expect("Failed to read input config!")).expect("Failed to parse input config!");
|
||||||
@@ -92,7 +113,7 @@ impl InputState {
|
|||||||
controller_input: Gilrs::new().unwrap() };
|
controller_input: Gilrs::new().unwrap() };
|
||||||
|
|
||||||
config.button.iter().for_each(|bn| {
|
config.button.iter().for_each(|bn| {
|
||||||
let modifiers = ModifiersState {
|
let modifiers = KeyboardModifierState {
|
||||||
shift: bn.shift.is_some(),
|
shift: bn.shift.is_some(),
|
||||||
ctrl: bn.ctrl.is_some(),
|
ctrl: bn.ctrl.is_some(),
|
||||||
alt: bn.alt.is_some(),
|
alt: bn.alt.is_some(),
|
||||||
@@ -138,7 +159,7 @@ impl InputState {
|
|||||||
AxisInput::Digital(positive_button, negative_button)
|
AxisInput::Digital(positive_button, negative_button)
|
||||||
},
|
},
|
||||||
InputConfigAxis { mouse_axis: Some(axis_name), .. } => {
|
InputConfigAxis { mouse_axis: Some(axis_name), .. } => {
|
||||||
let modifiers = ModifiersState {
|
let modifiers = KeyboardModifierState {
|
||||||
shift: axis.shift.is_some(),
|
shift: axis.shift.is_some(),
|
||||||
ctrl: axis.ctrl.is_some(),
|
ctrl: axis.ctrl.is_some(),
|
||||||
alt: axis.alt.is_some(),
|
alt: axis.alt.is_some(),
|
||||||
@@ -167,11 +188,11 @@ impl InputState {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_window_event(self: &mut Self, event: &Event) {
|
pub fn on_window_event(self: &mut Self, event: &Event<()>) {
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input }, .. } => {
|
Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input, .. }, .. } => {
|
||||||
if self.log_config.input_events {
|
if self.log_config.input_events {
|
||||||
let mods = mods_to_string(&input.modifiers);
|
let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&input.modifiers));
|
||||||
if mods.len() > 0 {
|
if mods.len() > 0 {
|
||||||
println!("Keyboard {:?} {:?} {:?} + {:?}", device_id, input.state, &mods, input.scancode)
|
println!("Keyboard {:?} {:?} {:?} + {:?}", device_id, input.state, &mods, input.scancode)
|
||||||
} else {
|
} else {
|
||||||
@@ -179,11 +200,11 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.on_keyboard_event(input.state, input.scancode, input.modifiers);
|
self.on_keyboard_event(input.state, input.scancode, KeyboardModifierState::from_deprecated_state(&input.modifiers));
|
||||||
},
|
},
|
||||||
Event::WindowEvent { event: WindowEvent::MouseInput { device_id, state, button, modifiers }, .. } => {
|
Event::WindowEvent { event: WindowEvent::MouseInput { device_id, state, button, modifiers }, .. } => {
|
||||||
if self.log_config.input_events {
|
if self.log_config.input_events {
|
||||||
let mods = mods_to_string(&modifiers);
|
let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&modifiers));
|
||||||
if mods.len() > 0 {
|
if mods.len() > 0 {
|
||||||
println!("Mouse {:?} {:?} {:?} + {:?}", device_id, state, &mods, button)
|
println!("Mouse {:?} {:?} {:?} + {:?}", device_id, state, &mods, button)
|
||||||
} else {
|
} else {
|
||||||
@@ -191,11 +212,11 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.on_mouse_event(state, button, modifiers);
|
self.on_mouse_event(state, button, &KeyboardModifierState::from_deprecated_state(&modifiers));
|
||||||
},
|
},
|
||||||
Event::WindowEvent { event: WindowEvent::MouseWheel { device_id, delta, phase, modifiers }, .. } => {
|
Event::WindowEvent { event: WindowEvent::MouseWheel { device_id, delta, phase, modifiers }, .. } => {
|
||||||
if self.log_config.input_events {
|
if self.log_config.input_events {
|
||||||
let mods = mods_to_string(&modifiers);
|
let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&modifiers));
|
||||||
if mods.len() > 0 {
|
if mods.len() > 0 {
|
||||||
println!("Scroll {:?} {:?} {:?} + {:?}", device_id, phase, &mods, delta)
|
println!("Scroll {:?} {:?} {:?} + {:?}", device_id, phase, &mods, delta)
|
||||||
} else {
|
} else {
|
||||||
@@ -203,7 +224,7 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.on_mouse_wheel_event(delta, modifiers);
|
self.on_mouse_wheel_event(delta, &KeyboardModifierState::from_deprecated_state(&modifiers));
|
||||||
},
|
},
|
||||||
Event::DeviceEvent { device_id, event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) } } => {
|
Event::DeviceEvent { device_id, event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) } } => {
|
||||||
if self.log_config.input_events {
|
if self.log_config.input_events {
|
||||||
@@ -269,10 +290,10 @@ impl InputState {
|
|||||||
axis.axis_inputs.iter().map(|item| {
|
axis.axis_inputs.iter().map(|item| {
|
||||||
match item {
|
match item {
|
||||||
AxisInput::Wheel(modifiers) => {
|
AxisInput::Wheel(modifiers) => {
|
||||||
if self.modifiers_are_pressed(*modifiers) { self.analog_wheel_state } else { 0.0 }
|
if self.modifiers_are_pressed(modifiers) { self.analog_wheel_state } else { 0.0 }
|
||||||
},
|
},
|
||||||
AxisInput::MouseMove(direction, modifiers) => {
|
AxisInput::MouseMove(direction, modifiers) => {
|
||||||
if self.modifiers_are_pressed(*modifiers) {
|
if self.modifiers_are_pressed(modifiers) {
|
||||||
match direction {
|
match direction {
|
||||||
MouseMoveDirection::X => self.mouse_delta_x as f32,
|
MouseMoveDirection::X => self.mouse_delta_x as f32,
|
||||||
MouseMoveDirection::Y => self.mouse_delta_y as f32,
|
MouseMoveDirection::Y => self.mouse_delta_y as f32,
|
||||||
@@ -301,11 +322,11 @@ impl InputState {
|
|||||||
match digital_input {
|
match digital_input {
|
||||||
DigitalInput::Keyboard(keyboard_input) => {
|
DigitalInput::Keyboard(keyboard_input) => {
|
||||||
self.pressed_scan_codes.contains(&keyboard_input.scan_code)
|
self.pressed_scan_codes.contains(&keyboard_input.scan_code)
|
||||||
&& self.modifiers_are_pressed(keyboard_input.modifiers)
|
&& self.modifiers_are_pressed(&keyboard_input.modifiers)
|
||||||
},
|
},
|
||||||
DigitalInput::Mouse(mouse_input) => {
|
DigitalInput::Mouse(mouse_input) => {
|
||||||
self.pressed_mouse_buttons.contains(&mouse_input.button)
|
self.pressed_mouse_buttons.contains(&mouse_input.button)
|
||||||
&& self.modifiers_are_pressed(mouse_input.modifiers)
|
&& self.modifiers_are_pressed(&mouse_input.modifiers)
|
||||||
},
|
},
|
||||||
DigitalInput::Wheel(wheel_input) => {
|
DigitalInput::Wheel(wheel_input) => {
|
||||||
self.input_events.contains(&DigitalInputEvent::Pressed(DigitalInput::Wheel(wheel_input.clone())))
|
self.input_events.contains(&DigitalInputEvent::Pressed(DigitalInput::Wheel(wheel_input.clone())))
|
||||||
@@ -316,7 +337,7 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modifiers_are_pressed(self: &Self, modifiers: ModifiersState) -> bool {
|
fn modifiers_are_pressed(self: &Self, modifiers: &KeyboardModifierState) -> bool {
|
||||||
(!modifiers.ctrl || self.pressed_scan_codes.contains(&29))
|
(!modifiers.ctrl || self.pressed_scan_codes.contains(&29))
|
||||||
&& (!modifiers.shift || self.pressed_scan_codes.contains(&42) || self.pressed_scan_codes.contains(&54))
|
&& (!modifiers.shift || self.pressed_scan_codes.contains(&42) || self.pressed_scan_codes.contains(&54))
|
||||||
&& (!modifiers.alt || self.pressed_scan_codes.contains(&56))
|
&& (!modifiers.alt || self.pressed_scan_codes.contains(&56))
|
||||||
@@ -327,7 +348,7 @@ impl InputState {
|
|||||||
if input.digital_inputs.iter().any(|di| self.digital_input_pressed(di)) { 1.0 } else { 0.0 }
|
if input.digital_inputs.iter().any(|di| self.digital_input_pressed(di)) { 1.0 } else { 0.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_keyboard_event(self: &mut Self, state: ElementState, scan_code: ScanCode, modifiers: ModifiersState) {
|
pub fn on_keyboard_event(self: &mut Self, state: ElementState, scan_code: ScanCode, modifiers: KeyboardModifierState) {
|
||||||
let input = DigitalInput::Keyboard(KeyboardInput { scan_code, modifiers });
|
let input = DigitalInput::Keyboard(KeyboardInput { scan_code, modifiers });
|
||||||
match state {
|
match state {
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
@@ -341,7 +362,7 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_mouse_event(self: &mut Self, state: &ElementState, button: &MouseButton, modifiers: &ModifiersState) {
|
pub fn on_mouse_event(self: &mut Self, state: &ElementState, button: &MouseButton, modifiers: &KeyboardModifierState) {
|
||||||
let input = DigitalInput::Mouse(MouseInput { button: button.clone(), modifiers: modifiers.clone() });
|
let input = DigitalInput::Mouse(MouseInput { button: button.clone(), modifiers: modifiers.clone() });
|
||||||
match state {
|
match state {
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
@@ -355,7 +376,7 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_mouse_wheel_event(self: &mut Self, delta: &MouseScrollDelta, modifiers: &ModifiersState) {
|
pub fn on_mouse_wheel_event(self: &mut Self, delta: &MouseScrollDelta, modifiers: &KeyboardModifierState) {
|
||||||
let vertical_direction = match delta {
|
let vertical_direction = match delta {
|
||||||
MouseScrollDelta::LineDelta(_x, y) => {
|
MouseScrollDelta::LineDelta(_x, y) => {
|
||||||
if *y > 0.0 { Some(WheelInputDirection::Up) }
|
if *y > 0.0 { Some(WheelInputDirection::Up) }
|
||||||
@@ -412,7 +433,7 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mods_to_string(modifiers: &ModifiersState) -> String {
|
fn mods_to_string(modifiers: &KeyboardModifierState) -> String {
|
||||||
String::from_iter(
|
String::from_iter(
|
||||||
vec!["shift", "ctrl", "alt", "logo"].iter()
|
vec!["shift", "ctrl", "alt", "logo"].iter()
|
||||||
.zip(vec![modifiers.shift, modifiers.ctrl, modifiers.alt, modifiers.logo])
|
.zip(vec![modifiers.shift, modifiers.ctrl, modifiers.alt, modifiers.logo])
|
||||||
@@ -422,8 +443,8 @@ fn mods_to_string(modifiers: &ModifiersState) -> String {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AxisInput {
|
pub enum AxisInput {
|
||||||
Wheel(ModifiersState),
|
Wheel(KeyboardModifierState),
|
||||||
MouseMove(MouseMoveDirection, ModifiersState),
|
MouseMove(MouseMoveDirection, KeyboardModifierState),
|
||||||
Digital(VirtualButton, VirtualButton),
|
Digital(VirtualButton, VirtualButton),
|
||||||
Controller(AnalogControllerInput),
|
Controller(AnalogControllerInput),
|
||||||
}
|
}
|
||||||
@@ -439,19 +460,19 @@ pub enum DigitalInput {
|
|||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
pub struct KeyboardInput {
|
pub struct KeyboardInput {
|
||||||
scan_code: ScanCode,
|
scan_code: ScanCode,
|
||||||
modifiers: ModifiersState,
|
modifiers: KeyboardModifierState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
pub struct MouseInput {
|
pub struct MouseInput {
|
||||||
button: MouseButton,
|
button: MouseButton,
|
||||||
modifiers: ModifiersState,
|
modifiers: KeyboardModifierState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
pub struct WheelInput {
|
pub struct WheelInput {
|
||||||
direction: WheelInputDirection,
|
direction: WheelInputDirection,
|
||||||
modifiers: ModifiersState,
|
modifiers: KeyboardModifierState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
@@ -474,7 +495,7 @@ pub enum MouseMoveDirection {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct AnalogWheelInput {
|
pub struct AnalogWheelInput {
|
||||||
value: f32,
|
value: f32,
|
||||||
modifiers: ModifiersState,
|
modifiers: KeyboardModifierState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
|||||||
60
src/main.rs
60
src/main.rs
@@ -1,16 +1,14 @@
|
|||||||
use winit::{Event};
|
use cgmath::{Deg, Matrix4, One, Quaternion, Rad, Rotation, Rotation3, Vector3};
|
||||||
use cgmath::{Matrix4, Rad, Vector3, Deg, Quaternion, Rotation3, One, Rotation};
|
use winit::event::Event;
|
||||||
|
|
||||||
mod vulkan;
|
use crate::config::LogConfig;
|
||||||
use crate::vulkan::{Game, LinePoint, GameObject, VulkanRenderer, RenderResult, MeshHandle, GameObjectHandle};
|
use crate::input::InputState;
|
||||||
|
use crate::vulkan::{Game, GameObject, GameObjectHandle, LinePoint, MeshHandle, VulkanRenderer};
|
||||||
use crate::vulkan::vs::ty::UniformBufferObject;
|
use crate::vulkan::vs::ty::UniformBufferObject;
|
||||||
|
|
||||||
|
mod vulkan;
|
||||||
mod input;
|
mod input;
|
||||||
use crate::input::{InputState};
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
use crate::config::LogConfig;
|
|
||||||
|
|
||||||
mod mesh;
|
mod mesh;
|
||||||
|
|
||||||
struct TestGame {
|
struct TestGame {
|
||||||
@@ -23,24 +21,9 @@ struct TestGame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Game for TestGame {
|
impl Game for TestGame {
|
||||||
fn on_window_event(self: &mut Self, event: &Event) {
|
fn on_window_event(self: &mut Self, event: &Event<()>) {
|
||||||
self.input.on_window_event(event);
|
self.input.on_window_event(event);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl TestGame {
|
|
||||||
fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) {
|
|
||||||
let (meshes, textures) = mesh::load_mesh("models/iski51.gltf", self.log_config.mesh_load_info).unwrap();
|
|
||||||
self.test_meshes = meshes.into_iter().map(|m| {
|
|
||||||
let id = match m.texture_index {
|
|
||||||
Some(tex_id) => tex_id + 1,
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
(renderer.upload_mesh(m), id)
|
|
||||||
}).collect();
|
|
||||||
textures.iter().for_each(|tex| renderer.upload_texture(tex));
|
|
||||||
println!("Game loaded!");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> UniformBufferObject {
|
fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> UniformBufferObject {
|
||||||
self.input.frame_start();
|
self.input.frame_start();
|
||||||
@@ -96,6 +79,21 @@ impl TestGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TestGame {
|
||||||
|
fn game_start(self: &mut Self, renderer: &mut VulkanRenderer) {
|
||||||
|
let (meshes, textures) = mesh::load_mesh("models/box.gltf", self.log_config.mesh_load_info).unwrap();
|
||||||
|
self.test_meshes = meshes.into_iter().map(|m| {
|
||||||
|
let id = match m.texture_index {
|
||||||
|
Some(tex_id) => tex_id + 1,
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
(renderer.upload_mesh(m), id)
|
||||||
|
}).collect();
|
||||||
|
textures.iter().for_each(|tex| renderer.upload_texture(tex));
|
||||||
|
println!("Game loaded!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let log_config = LogConfig::from_file("config/log.toml");
|
let log_config = LogConfig::from_file("config/log.toml");
|
||||||
|
|
||||||
@@ -109,7 +107,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let line_count = 30;
|
let line_count = 30;
|
||||||
let mut renderer = VulkanRenderer::init(
|
let (mut renderer, event_loop) = VulkanRenderer::init(
|
||||||
(-line_count..=line_count)
|
(-line_count..=line_count)
|
||||||
.flat_map(|it| vec![
|
.flat_map(|it| vec![
|
||||||
LinePoint { position: [it as f32, 0., -line_count as f32] },
|
LinePoint { position: [it as f32, 0., -line_count as f32] },
|
||||||
@@ -121,15 +119,5 @@ fn main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
game.game_start(&mut renderer);
|
game.game_start(&mut renderer);
|
||||||
|
vulkan::start_event_loop(renderer, Box::new(game), event_loop);
|
||||||
let mut continue_rendering = true;
|
|
||||||
let mut ubo = game.update(&mut renderer);
|
|
||||||
|
|
||||||
while continue_rendering {
|
|
||||||
match renderer.render_loop(&mut game, ubo) {
|
|
||||||
RenderResult::Ok => ubo = game.update(&mut renderer),
|
|
||||||
RenderResult::Reload => println!("Render loop reloaded..."),
|
|
||||||
RenderResult::Quit => continue_rendering = false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
325
src/vulkan.rs
325
src/vulkan.rs
@@ -1,42 +1,36 @@
|
|||||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
use std::sync::{Arc};
|
||||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, AutoCommandBuffer};
|
|
||||||
use vulkano::device::{Device, DeviceExtensions, Queue};
|
|
||||||
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
|
|
||||||
use vulkano::image::{SwapchainImage, AttachmentImage, ImageUsage, ImmutableImage, Dimensions};
|
|
||||||
use vulkano::instance::{Instance, PhysicalDevice, ApplicationInfo, Version, InstanceExtensions};
|
|
||||||
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
|
|
||||||
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule};
|
|
||||||
use vulkano::pipeline::viewport::Viewport;
|
|
||||||
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError, Surface};
|
|
||||||
use vulkano::swapchain;
|
|
||||||
use vulkano::sync::{GpuFuture, FlushError};
|
|
||||||
use vulkano::sync;
|
|
||||||
use vulkano::format::{Format, ClearValue};
|
|
||||||
use vulkano::instance::debug::{DebugCallback, MessageTypes};
|
|
||||||
use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc};
|
|
||||||
use vulkano::descriptor::descriptor_set::{FixedSizeDescriptorSetsPool, FixedSizeDescriptorSet, PersistentDescriptorSetBuf, PersistentDescriptorSetImg, PersistentDescriptorSetSampler};
|
|
||||||
use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode};
|
|
||||||
|
|
||||||
use vulkano_win::VkSurfaceBuild;
|
|
||||||
|
|
||||||
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent};
|
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use std::path::{PathBuf};
|
|
||||||
use std::ffi::{CStr};
|
|
||||||
|
|
||||||
use cgmath::{Matrix4, SquareMatrix};
|
use cgmath::{Matrix4, SquareMatrix};
|
||||||
|
use image::{ImageBuffer, ImageFormat, Rgb, Rgba};
|
||||||
|
use image::buffer::ConvertBuffer;
|
||||||
|
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||||
|
use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState};
|
||||||
|
use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet};
|
||||||
|
use vulkano::descriptor::DescriptorSet;
|
||||||
|
use vulkano::device::{Device, DeviceExtensions, Queue};
|
||||||
|
use vulkano::format::{ClearValue, Format};
|
||||||
|
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
|
||||||
|
use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImmutableImage, SwapchainImage};
|
||||||
|
use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version};
|
||||||
|
use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType};
|
||||||
|
use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc};
|
||||||
|
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
|
||||||
|
use vulkano::pipeline::viewport::Viewport;
|
||||||
|
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
|
||||||
|
use vulkano::swapchain::{AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError};
|
||||||
|
use vulkano::swapchain;
|
||||||
|
use vulkano::sync::{FlushError, GpuFuture};
|
||||||
|
use vulkano::sync;
|
||||||
|
use vulkano_win::VkSurfaceBuild;
|
||||||
|
use winit::event::{Event, WindowEvent};
|
||||||
|
use winit::event_loop::{EventLoop, ControlFlow};
|
||||||
|
use winit::window::{Window, WindowBuilder};
|
||||||
|
|
||||||
use shade_runner;
|
|
||||||
use shade_runner::{CompiledShaders, Entry};
|
|
||||||
use shaderc;
|
|
||||||
|
|
||||||
use vs::ty::PushConstants;
|
|
||||||
use line_vs::ty::LinePushConstants;
|
use line_vs::ty::LinePushConstants;
|
||||||
use crate::mesh::{CPUMesh};
|
use vs::ty::PushConstants;
|
||||||
|
|
||||||
use image::{ImageFormat, ConvertBuffer, ImageBuffer, Rgb, Rgba};
|
use crate::mesh::CPUMesh;
|
||||||
|
|
||||||
const VALIDATION_LAYERS: &[&str] = &[
|
const VALIDATION_LAYERS: &[&str] = &[
|
||||||
"VK_LAYER_LUNARG_standard_validation"
|
"VK_LAYER_LUNARG_standard_validation"
|
||||||
@@ -58,7 +52,9 @@ vulkano::impl_vertex!(LinePoint, position);
|
|||||||
|
|
||||||
pub trait Game {
|
pub trait Game {
|
||||||
/// Returns true if event should be ignored by the vulkan handler
|
/// Returns true if event should be ignored by the vulkan handler
|
||||||
fn on_window_event(self: &mut Self, event: &Event);
|
fn on_window_event(self: &mut Self, event: &Event<()>);
|
||||||
|
|
||||||
|
fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> vs::ty::UniformBufferObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Mesh {
|
pub struct Mesh {
|
||||||
@@ -75,10 +71,6 @@ pub struct GameObject {
|
|||||||
pub(crate) type GameObjectHandle = usize;
|
pub(crate) type GameObjectHandle = usize;
|
||||||
pub(crate) type MeshHandle = usize;
|
pub(crate) type MeshHandle = usize;
|
||||||
|
|
||||||
//type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((), PersistentDescriptorSetBuf<Arc<vulkano::buffer::cpu_access::CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>)>>;
|
|
||||||
//type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, (((), PersistentDescriptorSetBuf<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>)>>;
|
|
||||||
type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((((), PersistentDescriptorSetBuf<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>), PersistentDescriptorSetSampler)>>;
|
|
||||||
|
|
||||||
pub struct GameData {
|
pub struct GameData {
|
||||||
pub start_time: SystemTime,
|
pub start_time: SystemTime,
|
||||||
pub line_vertices: Vec<LinePoint>,
|
pub line_vertices: Vec<LinePoint>,
|
||||||
@@ -92,36 +84,30 @@ pub struct GameData {
|
|||||||
pub textures: Vec<Arc<ImmutableImage<Format>>>,
|
pub textures: Vec<Arc<ImmutableImage<Format>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Yeet = dyn DescriptorSet + Send + Sync;
|
||||||
|
|
||||||
pub struct VulkanRenderer {
|
pub struct VulkanRenderer {
|
||||||
pub game_data: GameData,
|
pub game_data: GameData,
|
||||||
pub device: Arc<Device>,
|
pub device: Arc<Device>,
|
||||||
pub framebuffers: Vec<Arc<FramebufferAbstract + Send + Sync>>,
|
pub framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
|
||||||
pub sampler: Arc<Sampler>,
|
pub sampler: Arc<Sampler>,
|
||||||
pub dynamic_state: DynamicState,
|
pub dynamic_state: DynamicState,
|
||||||
pub pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
|
pub pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
|
||||||
pub line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
|
pub line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
|
||||||
pub line_vertex_buffer: Arc<CpuAccessibleBuffer<[LinePoint], PotentialDedicatedAllocation<StdMemoryPoolAlloc>>>,
|
pub line_vertex_buffer: Arc<CpuAccessibleBuffer<[LinePoint], PotentialDedicatedAllocation<StdMemoryPoolAlloc>>>,
|
||||||
pub surface: Arc<Surface<Window>>,
|
pub surface: Arc<Surface<Window>>,
|
||||||
pub swapchain: Arc<Swapchain<Window>>,
|
pub swapchain: Arc<Swapchain<Window>>,
|
||||||
pub render_pass: Arc<RenderPassAbstract + Send + Sync>,
|
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
|
||||||
pub queue: Arc<Queue>,
|
pub queue: Arc<Queue>,
|
||||||
pub events_loop: EventsLoop,
|
|
||||||
pub recreate_swapchain: bool,
|
pub recreate_swapchain: bool,
|
||||||
pub debug_callback: Option<DebugCallback>,
|
pub debug_callback: Option<DebugCallback>,
|
||||||
pub previous_frame_end: Option<Box<GpuFuture>>,
|
pub previous_frame_end: Option<Box<dyn GpuFuture>>,
|
||||||
pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>,
|
pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>,
|
||||||
pub descriptor_sets: Vec<FixedGraphicsDescriptorSet>,
|
pub descriptor_sets: Vec<Arc<Yeet>>,
|
||||||
}
|
|
||||||
|
|
||||||
pub enum RenderResult {
|
|
||||||
/// Contains buffer index and swapchain future
|
|
||||||
Ok,
|
|
||||||
Reload,
|
|
||||||
Quit,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanRenderer {
|
impl VulkanRenderer {
|
||||||
pub fn init(line_vertices: Vec<LinePoint>, enable_validation_layers: bool) -> VulkanRenderer {
|
pub fn init(line_vertices: Vec<LinePoint>, enable_validation_layers: bool) -> (VulkanRenderer, EventLoop<()>) {
|
||||||
let mut data = GameData {
|
let mut data = GameData {
|
||||||
push_constants: PushConstants {
|
push_constants: PushConstants {
|
||||||
model: Matrix4::identity().into(),
|
model: Matrix4::identity().into(),
|
||||||
@@ -147,7 +133,7 @@ impl VulkanRenderer {
|
|||||||
|
|
||||||
let instance = {
|
let instance = {
|
||||||
let extensions = InstanceExtensions {
|
let extensions = InstanceExtensions {
|
||||||
ext_debug_report: true,
|
ext_debug_utils: true,
|
||||||
..vulkano_win::required_extensions()
|
..vulkano_win::required_extensions()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,20 +162,24 @@ impl VulkanRenderer {
|
|||||||
// lifetime of this is important, even tho it isn't used!
|
// lifetime of this is important, even tho it isn't used!
|
||||||
let mut debug_callback = None;
|
let mut debug_callback = None;
|
||||||
if enable_validation_layers {
|
if enable_validation_layers {
|
||||||
let msg_types = MessageTypes {
|
let msg_severity = MessageSeverity {
|
||||||
error: true,
|
verbose: false,
|
||||||
|
information: true,
|
||||||
warning: true,
|
warning: true,
|
||||||
performance_warning: true,
|
error: true
|
||||||
information: false,
|
|
||||||
debug: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_callback = DebugCallback::new(&instance, msg_types, |msg| {
|
let msg_types = MessageType {
|
||||||
let type_str = match (msg.ty.error, msg.ty.warning, msg.ty.performance_warning, msg.ty.information, msg.ty.debug) {
|
general: true,
|
||||||
(true, _, _, _, _) => "!!",
|
performance: true,
|
||||||
(_, true, _, _, _) => "!",
|
validation: true
|
||||||
(_, _, true, _, _) => "p",
|
};
|
||||||
(_, _, _, true, _) => "i",
|
|
||||||
|
debug_callback = DebugCallback::new(&instance, msg_severity, msg_types, |msg| {
|
||||||
|
let type_str = match (msg.severity.error, msg.severity.warning, msg.severity.information, msg.severity.verbose) {
|
||||||
|
(true, _, _, _) => "!!",
|
||||||
|
(_, true, _, _) => "!",
|
||||||
|
(_, _, _, true) => "i",
|
||||||
_ => " "
|
_ => " "
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -202,7 +192,7 @@ impl VulkanRenderer {
|
|||||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||||
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
|
||||||
|
|
||||||
let events_loop = EventsLoop::new();
|
let events_loop = EventLoop::new();
|
||||||
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
|
||||||
let window = surface.window();
|
let window = surface.window();
|
||||||
|
|
||||||
@@ -222,19 +212,16 @@ impl VulkanRenderer {
|
|||||||
let usage = caps.supported_usage_flags;
|
let usage = caps.supported_usage_flags;
|
||||||
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||||
let format = caps.supported_formats[0].0;
|
let format = caps.supported_formats[0].0;
|
||||||
data.dimensions = if let Some(dimensions) = window.get_inner_size() {
|
let inner_size = window.inner_size();
|
||||||
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
data.dimensions = [inner_size.width, inner_size.height];
|
||||||
[dimensions.0, dimensions.1]
|
|
||||||
} else {
|
|
||||||
panic!("Couldn't get window dimensions!");
|
|
||||||
};
|
|
||||||
|
|
||||||
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
|
||||||
data.dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
data.dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
|
||||||
PresentMode::Fifo, true, None).unwrap()
|
PresentMode::Fifo, FullscreenExclusive::Default, true, ColorSpace::SrgbNonLinear).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), data.line_vertices.iter().cloned()).unwrap();
|
// what is host_cached
|
||||||
|
let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap();
|
||||||
|
|
||||||
let render_pass = Arc::new(vulkano::single_pass_renderpass!(
|
let render_pass = Arc::new(vulkano::single_pass_renderpass!(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
@@ -264,14 +251,14 @@ impl VulkanRenderer {
|
|||||||
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
|
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
|
||||||
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap();
|
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap();
|
||||||
|
|
||||||
let pipeline: Arc<GraphicsPipelineAbstract + Send + Sync> =
|
let pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> =
|
||||||
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap();
|
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), false).unwrap();
|
||||||
let line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync> =
|
let line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> =
|
||||||
create_pipeline::<LinePoint>(device.clone(), render_pass.clone(), "shaders/line.vert", "shaders/line.frag", true).unwrap();
|
create_pipeline::<LinePoint>(device.clone(), render_pass.clone(), true).unwrap();
|
||||||
|
|
||||||
let default_tex = {
|
let default_tex = {
|
||||||
let image = image::load_from_memory_with_format(include_bytes!("../models/missing-texture.jpg"),
|
let image = image::load_from_memory_with_format(include_bytes!("../models/missing-texture.jpg"),
|
||||||
ImageFormat::JPEG).unwrap().to_rgba();
|
ImageFormat::Jpeg).unwrap().to_rgba();
|
||||||
let image_data = image.into_raw().clone();
|
let image_data = image.into_raw().clone();
|
||||||
|
|
||||||
let (image_view, future) = ImmutableImage::from_iter(
|
let (image_view, future) = ImmutableImage::from_iter(
|
||||||
@@ -288,7 +275,7 @@ impl VulkanRenderer {
|
|||||||
|
|
||||||
// Dynamic viewports allow us to recreate just the viewport when the window is resized
|
// Dynamic viewports allow us to recreate just the viewport when the window is resized
|
||||||
// Otherwise we would have to recreate the whole pipeline.
|
// Otherwise we would have to recreate the whole pipeline.
|
||||||
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
|
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: None };
|
||||||
|
|
||||||
// The render pass we created above only describes the layout of our framebuffers. Before we
|
// 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.
|
// can draw we also need to create the actual framebuffers.
|
||||||
@@ -301,22 +288,21 @@ impl VulkanRenderer {
|
|||||||
uniform_buffers.push(CpuAccessibleBuffer::from_data(
|
uniform_buffers.push(CpuAccessibleBuffer::from_data(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
BufferUsage::uniform_buffer_transfer_destination(),
|
BufferUsage::uniform_buffer_transfer_destination(),
|
||||||
|
false,
|
||||||
uniform_buffer,
|
uniform_buffer,
|
||||||
).unwrap());
|
).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let descriptor_set_pool = Mutex::new(FixedSizeDescriptorSetsPool::new(pipeline.clone(), 0));
|
let descriptor_set_layout = pipeline.descriptor_set_layout(0).unwrap().clone();
|
||||||
let descriptor_sets = uniform_buffers
|
|
||||||
.iter()
|
let descriptor_sets = uniform_buffers.iter().map(|uniform_buffer| {
|
||||||
.map(|uniform_buffer| {
|
let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone());
|
||||||
Arc::new(
|
let result: Arc<Yeet> = Arc::new(builder
|
||||||
descriptor_set_pool
|
|
||||||
.lock().unwrap().next()
|
|
||||||
.add_buffer(uniform_buffer.clone()).unwrap()
|
.add_buffer(uniform_buffer.clone()).unwrap()
|
||||||
.add_sampled_image(default_tex.clone(), sampler.clone()).unwrap()
|
.add_sampled_image(default_tex.clone(), sampler.clone()).unwrap()
|
||||||
.build().unwrap())
|
.build().unwrap());
|
||||||
})
|
result
|
||||||
.collect();
|
}).collect();
|
||||||
|
|
||||||
data.textures.push(default_tex);
|
data.textures.push(default_tex);
|
||||||
|
|
||||||
@@ -328,38 +314,38 @@ impl VulkanRenderer {
|
|||||||
// that, we store the submission of the previous frame here.
|
// that, we store the submission of the previous frame here.
|
||||||
let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
|
||||||
|
|
||||||
VulkanRenderer { game_data: data, device, framebuffers, sampler,
|
(VulkanRenderer { game_data: data, device, framebuffers, sampler,
|
||||||
dynamic_state, pipeline, line_pipeline, uniform_buffers, descriptor_sets,
|
dynamic_state, pipeline, line_pipeline, uniform_buffers, descriptor_sets,
|
||||||
surface, swapchain, render_pass, queue, line_vertex_buffer, events_loop,
|
surface, swapchain, render_pass, queue, line_vertex_buffer,
|
||||||
recreate_swapchain: false, debug_callback, previous_frame_end }
|
recreate_swapchain: false, debug_callback, previous_frame_end }, events_loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_command_buffer(self: &mut Self, fb_index: usize, ubo: vs::ty::UniformBufferObject) -> Arc<AutoCommandBuffer> {
|
fn create_command_buffer(self: &mut Self, fb_index: usize, ubo: vs::ty::UniformBufferObject) -> Arc<AutoCommandBuffer> {
|
||||||
let mut cbb = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap()
|
let mut builder = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap();
|
||||||
.update_buffer(self.uniform_buffers[fb_index].clone(), ubo).unwrap()
|
builder.update_buffer(self.uniform_buffers[fb_index].clone(), ubo).unwrap();
|
||||||
.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap();
|
builder.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap();
|
||||||
|
|
||||||
for i in 0..self.game_data.game_objects.len() {
|
for i in 0..self.game_data.game_objects.len() {
|
||||||
let game_object = &self.game_data.game_objects[i];
|
let game_object = &self.game_data.game_objects[i];
|
||||||
let mesh = &self.game_data.meshes[game_object.mesh_index];
|
let mesh = &self.game_data.meshes[game_object.mesh_index];
|
||||||
self.game_data.push_constants.model = game_object.model_matrix.into();
|
self.game_data.push_constants.model = game_object.model_matrix.into();
|
||||||
cbb = cbb.draw_indexed(
|
|
||||||
|
builder.draw_indexed(
|
||||||
self.pipeline.clone(),
|
self.pipeline.clone(),
|
||||||
&self.dynamic_state,
|
&self.dynamic_state,
|
||||||
vec![mesh.vertex_buffer.clone()],
|
vec![mesh.vertex_buffer.clone()],
|
||||||
mesh.index_buffer.clone(),
|
mesh.index_buffer.clone(),
|
||||||
self.descriptor_sets[fb_index].clone(),
|
self.descriptor_sets[fb_index].clone(),
|
||||||
self.game_data.push_constants.clone()).unwrap()
|
self.game_data.push_constants.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
cbb = cbb.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap()
|
builder.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap()
|
||||||
.end_render_pass().unwrap();
|
.end_render_pass().unwrap();
|
||||||
|
|
||||||
Arc::new(cbb.build().unwrap())
|
Arc::new(builder.build().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns false if rendering should stop
|
pub fn render_loop(self: &mut Self, new_ubo: vs::ty::UniformBufferObject) {
|
||||||
pub fn render_loop(self: &mut Self, game: &mut dyn Game, new_ubo: vs::ty::UniformBufferObject) -> RenderResult {
|
|
||||||
// It is important to call this function from time to time, otherwise resources will keep
|
// It is important to call this function from time to time, otherwise resources will keep
|
||||||
// accumulating and you will eventually reach an out of memory error.
|
// accumulating and you will eventually reach an out of memory error.
|
||||||
// Calling this function polls various fences in order to determine what the GPU has
|
// Calling this function polls various fences in order to determine what the GPU has
|
||||||
@@ -368,20 +354,16 @@ impl VulkanRenderer {
|
|||||||
|
|
||||||
if self.recreate_swapchain {
|
if self.recreate_swapchain {
|
||||||
let window = self.surface.window();
|
let window = self.surface.window();
|
||||||
self.game_data.dimensions = if let Some(dimensions) = window.get_inner_size() {
|
let inner_size = window.inner_size();
|
||||||
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
|
self.game_data.dimensions = [inner_size.width, inner_size.height];
|
||||||
[dimensions.0, dimensions.1]
|
|
||||||
} else {
|
|
||||||
panic!("Window no longer exists!");
|
|
||||||
};
|
|
||||||
|
|
||||||
let (new_swapchain, new_images) = match self.swapchain.recreate_with_dimension(self.game_data.dimensions) {
|
let (new_swapchain, new_images) = match self.swapchain.recreate_with_dimensions(self.game_data.dimensions) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
// This error tends to happen when the user is manually resizing the window.
|
// This error tends to happen when the user is manually resizing the window.
|
||||||
// Simply restarting the loop is the easiest way to fix this issue.
|
// Simply restarting the loop is the easiest way to fix this issue.
|
||||||
Err(SwapchainCreationError::UnsupportedDimensions) => {
|
Err(SwapchainCreationError::UnsupportedDimensions) => {
|
||||||
println!("Swapchain rejected: UnsupportedDimensions");
|
println!("Swapchain rejected: UnsupportedDimensions");
|
||||||
return RenderResult::Reload;
|
return;
|
||||||
}
|
}
|
||||||
Err(err) => panic!("{:?}", err),
|
Err(err) => panic!("{:?}", err),
|
||||||
};
|
};
|
||||||
@@ -395,7 +377,7 @@ impl VulkanRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.game_data.recreate_pipeline {
|
if self.game_data.recreate_pipeline {
|
||||||
if let Some(pipeline_ok) = create_pipeline::<Vertex>(self.device.clone(), self.render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false) {
|
if let Some(pipeline_ok) = create_pipeline::<Vertex>(self.device.clone(), self.render_pass.clone(), false) {
|
||||||
self.pipeline = pipeline_ok;
|
self.pipeline = pipeline_ok;
|
||||||
println!("Updated pipeline.");
|
println!("Updated pipeline.");
|
||||||
} else {
|
} else {
|
||||||
@@ -411,11 +393,11 @@ impl VulkanRenderer {
|
|||||||
//
|
//
|
||||||
// This function can block if no image is available. The parameter is an optional timeout
|
// This function can block if no image is available. The parameter is an optional timeout
|
||||||
// after which the function call will return an error.
|
// after which the function call will return an error.
|
||||||
let (fb_index, acquire_future) = match swapchain::acquire_next_image(self.swapchain.clone(), None) {
|
let (fb_index, _, acquire_future) = match swapchain::acquire_next_image(self.swapchain.clone(), None) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(AcquireError::OutOfDate) => {
|
Err(AcquireError::OutOfDate) => {
|
||||||
self.recreate_swapchain = true;
|
self.recreate_swapchain = true;
|
||||||
return RenderResult::Reload;
|
return;
|
||||||
},
|
},
|
||||||
Err(err) => panic!("{:?}", err)
|
Err(err) => panic!("{:?}", err)
|
||||||
};
|
};
|
||||||
@@ -451,33 +433,11 @@ impl VulkanRenderer {
|
|||||||
self.previous_frame_end = Some(Box::new(sync::now(self.device.clone())) as Box<_>);
|
self.previous_frame_end = Some(Box::new(sync::now(self.device.clone())) as Box<_>);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note that in more complex programs it is likely that one of `acquire_next_image`,
|
|
||||||
// `command_buffer::submit`, or `present` will block for some time. This happens when the
|
|
||||||
// GPU's queue is full and the driver has to wait until the GPU finished some work.
|
|
||||||
//
|
|
||||||
// Unfortunately the Vulkan API doesn't provide any way to not wait or to detect when a
|
|
||||||
// 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.
|
|
||||||
let mut window_closed = false;
|
|
||||||
let mut resized = false;
|
|
||||||
self.events_loop.poll_events(|ev| {
|
|
||||||
game.on_window_event(&ev);
|
|
||||||
match ev {
|
|
||||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => window_closed = true,
|
|
||||||
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => resized = true,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if resized { self.recreate_swapchain = true }
|
|
||||||
if self.game_data.shutdown || window_closed { return RenderResult::Quit; }
|
|
||||||
|
|
||||||
RenderResult::Ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upload_mesh(self: &mut Self, mesh: CPUMesh) -> usize {
|
pub fn upload_mesh(self: &mut Self, mesh: CPUMesh) -> usize {
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), mesh.vertices.into_iter()).unwrap();
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), false, mesh.vertices.into_iter()).unwrap();
|
||||||
let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), mesh.indices.into_iter()).unwrap();
|
let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), false, mesh.indices.into_iter()).unwrap();
|
||||||
self.game_data.meshes.push(Mesh { vertex_buffer, index_buffer });
|
self.game_data.meshes.push(Mesh { vertex_buffer, index_buffer });
|
||||||
self.game_data.meshes.len() - 1
|
self.game_data.meshes.len() - 1
|
||||||
}
|
}
|
||||||
@@ -504,6 +464,27 @@ impl VulkanRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_event_loop(mut renderer: VulkanRenderer, mut game: Box<dyn Game>, event_loop: EventLoop<()>) {
|
||||||
|
let mut recreate_swapchain = false;
|
||||||
|
let ubo = game.update(&mut renderer);
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
},
|
||||||
|
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
},
|
||||||
|
Event::RedrawEventsCleared => {
|
||||||
|
game.update(&mut renderer);
|
||||||
|
renderer.render_loop(ubo);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// This method is called once during initialization, then again whenever the window is resized
|
/// This method is called once during initialization, then again whenever the window is resized
|
||||||
fn window_size_dependent_setup(device: Arc<Device>, images: &[Arc<SwapchainImage<Window>>], render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, dynamic_state: &mut DynamicState) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
fn window_size_dependent_setup(device: Arc<Device>, images: &[Arc<SwapchainImage<Window>>], render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, dynamic_state: &mut DynamicState) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||||
let dimensions = images[0].dimensions();
|
let dimensions = images[0].dimensions();
|
||||||
@@ -554,52 +535,35 @@ pub mod line_fs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, render_pass: Arc<RenderPassAbstract + Send + Sync>, vertex_shader_path: &str, fragment_shader_path: &str, is_line: bool) -> Option<Arc<GraphicsPipelineAbstract + Send + Sync>> {
|
fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, is_line: bool) -> Option<Arc<dyn GraphicsPipelineAbstract + Send + Sync>> {
|
||||||
if let Some((shader, shader_data)) = read_shader(vertex_shader_path, fragment_shader_path) {
|
|
||||||
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
|
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||||
|
|
||||||
let vertex_shader_entry;
|
|
||||||
let fragment_shader_entry;
|
|
||||||
let vertex_shader_module;
|
|
||||||
let fragment_shader_module;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
vertex_shader_module = ShaderModule::from_words(device.clone(), &shader.vertex).expect("Failed to load vertex shader.");
|
|
||||||
vertex_shader_entry = vertex_shader_module.graphics_entry_point(
|
|
||||||
CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
|
||||||
shader_data.vert_input,
|
|
||||||
shader_data.vert_output,
|
|
||||||
shader_data.vert_layout,
|
|
||||||
GraphicsShaderType::Vertex);
|
|
||||||
fragment_shader_module = ShaderModule::from_words(device.clone(), &shader.fragment).expect("Failed to load fragment shader.");
|
|
||||||
fragment_shader_entry = fragment_shader_module.graphics_entry_point(
|
|
||||||
CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
|
||||||
shader_data.frag_input,
|
|
||||||
shader_data.frag_output,
|
|
||||||
shader_data.frag_layout,
|
|
||||||
GraphicsShaderType::Fragment);
|
|
||||||
};
|
|
||||||
|
|
||||||
let pipeline;
|
let pipeline;
|
||||||
|
|
||||||
if is_line {
|
if is_line {
|
||||||
|
let vertex_shader = line_vs::Shader::load(device.clone()).unwrap();
|
||||||
|
let fragment_shader = line_fs::Shader::load(device.clone()).unwrap();
|
||||||
|
|
||||||
pipeline = Arc::new(GraphicsPipeline::start()
|
pipeline = Arc::new(GraphicsPipeline::start()
|
||||||
.vertex_input_single_buffer::<V>()
|
.vertex_input_single_buffer::<V>()
|
||||||
.vertex_shader(vertex_shader_entry.clone(), ())
|
.vertex_shader(vertex_shader.main_entry_point(), ())
|
||||||
.line_list()
|
.line_list()
|
||||||
.viewports_dynamic_scissors_irrelevant(1)
|
.viewports_dynamic_scissors_irrelevant(1)
|
||||||
.depth_stencil_simple_depth()
|
.depth_stencil_simple_depth()
|
||||||
.fragment_shader(fragment_shader_entry.clone(), ())
|
.fragment_shader(fragment_shader.main_entry_point(), ())
|
||||||
.render_pass(sub_pass.clone())
|
.render_pass(sub_pass.clone())
|
||||||
.build(device.clone())
|
.build(device.clone())
|
||||||
.unwrap());
|
.unwrap());
|
||||||
} else {
|
} else {
|
||||||
|
let vertex_shader = vs::Shader::load(device.clone()).unwrap();
|
||||||
|
let fragment_shader = fs::Shader::load(device.clone()).unwrap();
|
||||||
|
|
||||||
pipeline = Arc::new(GraphicsPipeline::start()
|
pipeline = Arc::new(GraphicsPipeline::start()
|
||||||
.vertex_input_single_buffer::<V>()
|
.vertex_input_single_buffer::<V>()
|
||||||
.vertex_shader(vertex_shader_entry.clone(), ())
|
.vertex_shader(vertex_shader.main_entry_point(), ())
|
||||||
.triangle_list()
|
.triangle_list()
|
||||||
.viewports_dynamic_scissors_irrelevant(1)
|
.viewports_dynamic_scissors_irrelevant(1)
|
||||||
.depth_stencil_simple_depth()
|
.depth_stencil_simple_depth()
|
||||||
.fragment_shader(fragment_shader_entry.clone(), ())
|
.fragment_shader(fragment_shader.main_entry_point(), ())
|
||||||
.blend_alpha_blending()
|
.blend_alpha_blending()
|
||||||
.cull_mode_back()
|
.cull_mode_back()
|
||||||
.render_pass(sub_pass.clone())
|
.render_pass(sub_pass.clone())
|
||||||
@@ -608,9 +572,6 @@ fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Some(pipeline);
|
return Some(pipeline);
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameObject {
|
impl GameObject {
|
||||||
@@ -618,29 +579,3 @@ impl GameObject {
|
|||||||
GameObject { mesh_index: mesh, texture_index, model_matrix: Matrix4::identity() }
|
GameObject { mesh_index: mesh, texture_index, model_matrix: Matrix4::identity() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_shader(vert_path_relative: &str, frag_path_relative: &str) -> Option<(CompiledShaders, Entry)> {
|
|
||||||
let project_root = std::env::current_dir().expect("failed to get root directory");
|
|
||||||
|
|
||||||
let mut vert_path = project_root.clone();
|
|
||||||
vert_path.push(PathBuf::from(vert_path_relative));
|
|
||||||
|
|
||||||
let mut frag_path = project_root.clone();
|
|
||||||
frag_path.push(PathBuf::from(frag_path_relative));
|
|
||||||
|
|
||||||
let shader_result = shade_runner::load(vert_path, frag_path);
|
|
||||||
match shader_result {
|
|
||||||
Ok(shader) => {
|
|
||||||
let shader_data = shade_runner::parse(&shader).expect("Failed to parse");
|
|
||||||
return Some((shader, shader_data));
|
|
||||||
}
|
|
||||||
Err(shade_runner::error::Error::Compile(shade_runner::error::CompileError::Compile(shaderc::Error::CompilationError(line, error)))) => {
|
|
||||||
println!("Shader line {}: {:?}", line, error);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
println!("Shader compilation error: {:?}", error);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user