Fix and module update

This commit is contained in:
2020-06-25 00:59:10 +02:00
parent ae8b82c84d
commit e755d3b1d8
4 changed files with 235 additions and 293 deletions

View File

@@ -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"

View File

@@ -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)]

View File

@@ -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,
}
}
} }

View File

@@ -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 .add_buffer(uniform_buffer.clone()).unwrap()
.lock().unwrap().next() .add_sampled_image(default_tex.clone(), sampler.clone()).unwrap()
.add_buffer(uniform_buffer.clone()).unwrap() .build().unwrap());
.add_sampled_image(default_tex.clone(), sampler.clone()).unwrap() result
.build().unwrap()) }).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,93 +535,47 @@ 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 pipeline;
let vertex_shader_entry; if is_line {
let fragment_shader_entry; let vertex_shader = line_vs::Shader::load(device.clone()).unwrap();
let vertex_shader_module; let fragment_shader = line_fs::Shader::load(device.clone()).unwrap();
let fragment_shader_module;
unsafe { pipeline = Arc::new(GraphicsPipeline::start()
vertex_shader_module = ShaderModule::from_words(device.clone(), &shader.vertex).expect("Failed to load vertex shader."); .vertex_input_single_buffer::<V>()
vertex_shader_entry = vertex_shader_module.graphics_entry_point( .vertex_shader(vertex_shader.main_entry_point(), ())
CStr::from_bytes_with_nul_unchecked(b"main\0"), .line_list()
shader_data.vert_input, .viewports_dynamic_scissors_irrelevant(1)
shader_data.vert_output, .depth_stencil_simple_depth()
shader_data.vert_layout, .fragment_shader(fragment_shader.main_entry_point(), ())
GraphicsShaderType::Vertex); .render_pass(sub_pass.clone())
fragment_shader_module = ShaderModule::from_words(device.clone(), &shader.fragment).expect("Failed to load fragment shader."); .build(device.clone())
fragment_shader_entry = fragment_shader_module.graphics_entry_point( .unwrap());
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;
if is_line {
pipeline = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<V>()
.vertex_shader(vertex_shader_entry.clone(), ())
.line_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fragment_shader_entry.clone(), ())
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
} else {
pipeline = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<V>()
.vertex_shader(vertex_shader_entry.clone(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fragment_shader_entry.clone(), ())
.blend_alpha_blending()
.cull_mode_back()
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
}
return Some(pipeline);
} else { } else {
return None; let vertex_shader = vs::Shader::load(device.clone()).unwrap();
let fragment_shader = fs::Shader::load(device.clone()).unwrap();
pipeline = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<V>()
.vertex_shader(vertex_shader.main_entry_point(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fragment_shader.main_entry_point(), ())
.blend_alpha_blending()
.cull_mode_back()
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
} }
return Some(pipeline);
} }
impl GameObject { impl GameObject {
pub fn new(mesh: MeshHandle, texture_index: usize) -> GameObject { pub fn new(mesh: MeshHandle, texture_index: usize) -> 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;
}
}
} }