Implemented Controller
* reworked input system + added Subengines system + added Subengines pipeline system !(old) some framebuffer error present !(old) may crash during swapchain recreation ! crashes randomly while running
This commit is contained in:
parent
5f9cc86689
commit
7f37ee7a24
File diff suppressed because one or more lines are too long
166
src/controller.rs
Normal file
166
src/controller.rs
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
io::{Input, Output},
|
||||||
|
subengine::SubenginePipeline,
|
||||||
|
};
|
||||||
|
|
||||||
|
//--Controller Implementation-----------------------------------------------------------------------
|
||||||
|
pub struct Controller<'a, I, W, O>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
|
O: Output<W>,
|
||||||
|
{
|
||||||
|
pipelines: Vec<SubenginePipeline<'a, I, W, O>>,
|
||||||
|
color: [f32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, W, O> Controller<'_, I, W, O>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
|
O: Output<W>,
|
||||||
|
{
|
||||||
|
|
||||||
|
pub fn new<'a, Ip>(pipelines: Ip) -> Controller<'a, I, W, O>
|
||||||
|
where
|
||||||
|
I: 'a + Input,
|
||||||
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
|
O: 'a + Output<W>,
|
||||||
|
Ip: IntoIterator<Item = SubenginePipeline<'a, I, W, O>>,
|
||||||
|
{
|
||||||
|
let pipelines_vec = pipelines
|
||||||
|
.into_iter()
|
||||||
|
.map(|pipeline| pipeline)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Controller {
|
||||||
|
pipelines: pipelines_vec,
|
||||||
|
color: [0.0, 1.0, 0.0, 0.0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
subengine::subengine_controller::SubengineCommand,
|
||||||
|
io::Key,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut input_keys: Vec<Key> = Vec::new();
|
||||||
|
|
||||||
|
for pipeline in &mut self.pipelines {
|
||||||
|
for input in &pipeline.inputs {
|
||||||
|
match input.borrow().read(1) {
|
||||||
|
Ok(key) => input_keys.push(key),
|
||||||
|
Err(_err) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for input_key in &input_keys {
|
||||||
|
match input_key {
|
||||||
|
Key::MouseMove{x,y} => self.color = [
|
||||||
|
(x/1280.0) as f32,
|
||||||
|
(y/720.0) as f32,
|
||||||
|
((x/1280.0 + y/720.0)/2.0) as f32,
|
||||||
|
1.0],
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for subengines in &pipeline.subengines {
|
||||||
|
for subengine in subengines {
|
||||||
|
subengine.exec(SubengineCommand::Run);
|
||||||
|
}
|
||||||
|
for subengine in subengines {
|
||||||
|
subengine.wait_for_exec(Duration::from_millis(1)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (renderer, output) in &mut pipeline.renderers {
|
||||||
|
match renderer.draw_clear_frame(output, self.color) {
|
||||||
|
Err(err) => warn!("{}", err),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
winit_window::WinitWindow,
|
||||||
|
renderer::Renderer,
|
||||||
|
utils::Rect,
|
||||||
|
subengine::{SubengineController, TestSubengine},
|
||||||
|
};
|
||||||
|
|
||||||
|
use gfx_backend_vulkan as vk_back;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new() {
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
//creating windows
|
||||||
|
let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap());
|
||||||
|
let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap());
|
||||||
|
|
||||||
|
//creating renderers
|
||||||
|
let renderer1 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window1)).unwrap();
|
||||||
|
let renderer2 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window2)).unwrap();
|
||||||
|
|
||||||
|
//creating subengines
|
||||||
|
let (test_subengine1, _test_rx1) = TestSubengine::new("run1");
|
||||||
|
let test_controller1 = SubengineController::new(test_subengine1);
|
||||||
|
let (test_subengine2, _test_rx2) = TestSubengine::new("run2");
|
||||||
|
let test_controller2 = SubengineController::new(test_subengine2);
|
||||||
|
|
||||||
|
//preparing data
|
||||||
|
let inputs = vec![&window1, &window2];
|
||||||
|
let subengines = vec![vec![test_controller1, test_controller2]];
|
||||||
|
let renderers = vec![(renderer1, &window1), (renderer2, &window2)];
|
||||||
|
|
||||||
|
//creating pipeline
|
||||||
|
let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers);
|
||||||
|
|
||||||
|
//creating controller
|
||||||
|
let controller = Controller::new(vec![subengine_pipeline]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_run() {
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
//creating windows
|
||||||
|
let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap());
|
||||||
|
let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap());
|
||||||
|
|
||||||
|
//creating renderers
|
||||||
|
let renderer1 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window1)).unwrap();
|
||||||
|
let renderer2 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window2)).unwrap();
|
||||||
|
|
||||||
|
//creating subengines
|
||||||
|
let (test_subengine1, _test_rx1) = TestSubengine::new("run1");
|
||||||
|
let test_controller1 = SubengineController::new(test_subengine1);
|
||||||
|
let (test_subengine2, _test_rx2) = TestSubengine::new("run2");
|
||||||
|
let test_controller2 = SubengineController::new(test_subengine2);
|
||||||
|
|
||||||
|
//preparing data
|
||||||
|
let inputs = vec![&window1, &window2];
|
||||||
|
let subengines = vec![vec![test_controller1, test_controller2]];
|
||||||
|
let renderers = vec![(renderer1, &window1), (renderer2, &window2)];
|
||||||
|
|
||||||
|
//creating pipeline
|
||||||
|
let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers);
|
||||||
|
|
||||||
|
//running controller
|
||||||
|
let mut controller = Controller::new(vec![subengine_pipeline]);
|
||||||
|
controller.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
42
src/input.rs
42
src/input.rs
@ -1,42 +0,0 @@
|
|||||||
#[allow(unused_imports)]
|
|
||||||
use log::{debug, error, info, trace, warn};
|
|
||||||
|
|
||||||
use winit::{
|
|
||||||
event::{Event, WindowEvent},
|
|
||||||
event_loop::{ControlFlow, EventLoop},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Input {
|
|
||||||
pub close_request: bool,
|
|
||||||
pub new_frame_size: Option<(f64, f64)>,
|
|
||||||
pub new_mouse_pos: Option<(f64, f64)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Input {
|
|
||||||
|
|
||||||
pub fn poll_events_loop(event_loop: &mut EventLoop<()>) -> Self {
|
|
||||||
let mut input = Input::default();
|
|
||||||
event_loop.run(|event, _, control_flow| {
|
|
||||||
*control_flow = ControlFlow::Wait;
|
|
||||||
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent{window_id: _, event} => match event {
|
|
||||||
WindowEvent::CloseRequested => (),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
input
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default() -> Self {
|
|
||||||
Input {
|
|
||||||
close_request: false,
|
|
||||||
new_frame_size: None,
|
|
||||||
new_mouse_pos: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
98
src/io.rs
Normal file
98
src/io.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use raw_window_handle::HasRawWindowHandle;
|
||||||
|
|
||||||
|
use crate::utils::Rect;
|
||||||
|
|
||||||
|
//--Output trait------------------------------------------------------------------------------------
|
||||||
|
/// A trait for the ability of a type to be used as an output by the engine.
|
||||||
|
///
|
||||||
|
/// The `Output` trait defines functions to be used by different components of the engine. This
|
||||||
|
/// allows to display with any window manager as long as the trait is defined for it.
|
||||||
|
///
|
||||||
|
/// Types that implement the `Output` trait should manage the underlying window and settings.
|
||||||
|
///
|
||||||
|
/// Implementation : the ID and size stored by the type implementing this trait don't need to be
|
||||||
|
/// initialized to anything specific as the engine will take care of it.
|
||||||
|
pub trait Output<W>
|
||||||
|
where
|
||||||
|
W: HasRawWindowHandle,
|
||||||
|
{
|
||||||
|
/// Return the ID stored internally. Used to select the right swapchain by the render engine.
|
||||||
|
/// For internal use only.
|
||||||
|
fn get_id(&self) -> usize;
|
||||||
|
|
||||||
|
/// Store the given ID internally. For internal use only.
|
||||||
|
fn set_id(&mut self, id: usize);
|
||||||
|
|
||||||
|
//TODO clean that
|
||||||
|
/// Give mutable acces to the size of the output. The size is a simple rectangle containing the
|
||||||
|
/// width and height of the `Output`.
|
||||||
|
fn size(&mut self) -> &mut Rect<i32>;
|
||||||
|
|
||||||
|
/// Give reference acces to the underlying window. This is used by the engine during setup to
|
||||||
|
/// create the revelant ressources.
|
||||||
|
fn window(&self) -> &W;
|
||||||
|
}
|
||||||
|
|
||||||
|
//impl<'a, W, O> Output<W> for &'a mut O
|
||||||
|
//where
|
||||||
|
// W: HasRawWindowHandle,
|
||||||
|
// O: Output<W>,
|
||||||
|
//{
|
||||||
|
// fn get_id(&self) -> usize { Output::get_id(*self) }
|
||||||
|
// fn set_id(&mut self, id: usize) { Output::set_id(*self, id); }
|
||||||
|
//
|
||||||
|
// fn size(&mut self) -> &mut Rect<i32> { Output::size(*self) }
|
||||||
|
//
|
||||||
|
// fn window(&self) -> &W { Output::window(*self) }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//impl<'a, W, O> Output<W> for Box<O>
|
||||||
|
//where
|
||||||
|
// W: HasRawWindowHandle,
|
||||||
|
// O: Output<W>,
|
||||||
|
//{
|
||||||
|
// fn get_id(&self) -> usize { Output::get_id(self) }
|
||||||
|
// fn set_id(&mut self, id: usize) { Output::set_id(self, id); }
|
||||||
|
//
|
||||||
|
// fn size(&mut self) -> &mut Rect<i32> { Output::size(self) }
|
||||||
|
//
|
||||||
|
// fn window(&self) -> &W { Output::window(self) }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//--Input trait------------------------------------------------------------------------------------
|
||||||
|
/// A trait for the ability of a type to be used as an input by the engine
|
||||||
|
///
|
||||||
|
/// The `Input` trait defines functions used by different components of the engine. The allow to
|
||||||
|
/// read inputs from any window manzger as long as the is defined for it.
|
||||||
|
///
|
||||||
|
/// Types that implement the `Input` trait should manage the EventLoop. This can be done in any way
|
||||||
|
/// (polling, interrupt, synchronous, asynchronous, ...) depending on how the input should be
|
||||||
|
/// handled.
|
||||||
|
pub trait Input {
|
||||||
|
/// Return the next input available or a ReadError if an error occured of the timeout duration
|
||||||
|
/// was reached. How inputs are handled depends on the implementation.
|
||||||
|
//TODO change timeout
|
||||||
|
fn read(&self, timeout_ms: u32) -> Result<Key, ReadError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//impl<'a, I> Input for &'a mut I
|
||||||
|
//where
|
||||||
|
// I: Input,
|
||||||
|
//{
|
||||||
|
// fn read(&self, timeout_ms: u32) -> Result<Key, ReadError> { Input::read(*self, timeout_ms) }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//--Key enum----------------------------------------------------------------------------------------
|
||||||
|
pub enum Key {
|
||||||
|
Close,
|
||||||
|
MouseMove { x: f64, y: f64 },
|
||||||
|
}
|
||||||
|
|
||||||
|
//--ReadError enum----------------------------------------------------------------------------------
|
||||||
|
pub enum ReadError {
|
||||||
|
Timeout,
|
||||||
|
}
|
||||||
|
|
||||||
116
src/lib.rs
116
src/lib.rs
@ -5,31 +5,32 @@
|
|||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
//use std::{
|
|
||||||
// sync::mpsc,
|
|
||||||
// thread,
|
|
||||||
// collections::HashMap,
|
|
||||||
// cell::RefCell,
|
|
||||||
//};
|
|
||||||
|
|
||||||
use gfx_backend_vulkan as vk_back;
|
use gfx_backend_vulkan as vk_back;
|
||||||
|
|
||||||
|
pub mod io;
|
||||||
|
|
||||||
|
pub mod subengine;
|
||||||
|
use subengine::SubenginePipeline;
|
||||||
|
|
||||||
|
pub mod controller;
|
||||||
|
use controller::Controller;
|
||||||
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
use crate::utils::Rect;
|
//use utils::Rect;
|
||||||
|
|
||||||
mod winit_window;
|
mod winit_window;
|
||||||
use winit_window::WinitWindow;
|
//use winit_window::WinitWindow;
|
||||||
|
|
||||||
//use winit::{
|
|
||||||
// event::{Event, WindowEvent},
|
|
||||||
// event_loop::ControlFlow,
|
|
||||||
//};
|
|
||||||
|
|
||||||
mod renderer;
|
mod renderer;
|
||||||
use renderer::Renderer;
|
//use renderer::Renderer;
|
||||||
|
|
||||||
//mod local_state;
|
//mod controller;
|
||||||
//use local_state::LocalState;
|
//use controller::Controller;
|
||||||
|
|
||||||
|
//use crate::engine::{
|
||||||
|
// EngineController,
|
||||||
|
// TestEngine,
|
||||||
|
//};
|
||||||
|
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
NoCommand,
|
NoCommand,
|
||||||
@ -56,24 +57,73 @@ pub enum Input {
|
|||||||
|
|
||||||
/// The main function of the library
|
/// The main function of the library
|
||||||
pub fn run() -> Result<(), &'static str> {
|
pub fn run() -> Result<(), &'static str> {
|
||||||
|
use std::{
|
||||||
let mut windows = vec![
|
iter,
|
||||||
WinitWindow::new("IV", Rect {w: 1280, h: 720})?,
|
cell::RefCell,
|
||||||
// WinitWindow::new("IV 2", Rect {w: 720, h: 480})?,
|
};
|
||||||
];
|
|
||||||
|
|
||||||
let mut renderer: Renderer<vk_back::Backend> = Renderer::new(&mut windows)?;
|
use crate::{
|
||||||
|
winit_window::WinitWindow,
|
||||||
|
renderer::Renderer,
|
||||||
|
utils::Rect,
|
||||||
|
subengine::{SubengineController, TestSubengine},
|
||||||
|
};
|
||||||
|
|
||||||
|
//creating windows
|
||||||
|
let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap());
|
||||||
|
//let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap());
|
||||||
|
|
||||||
|
//creating renderers
|
||||||
|
let renderer1 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window1)).unwrap();
|
||||||
|
//let renderer2 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window2)).unwrap();
|
||||||
|
|
||||||
|
//creating subengines
|
||||||
|
let (test_subengine1, _test_rx1) = TestSubengine::new("run1");
|
||||||
|
let test_controller1 = SubengineController::new(test_subengine1);
|
||||||
|
//let (test_subengine2, _test_rx2) = TestSubengine::new("run2");
|
||||||
|
//let test_controller2 = SubengineController::new(test_subengine2);
|
||||||
|
|
||||||
|
//preparing data
|
||||||
|
let inputs = vec![&window1];
|
||||||
|
let subengines = vec![vec![test_controller1/*, test_controller2*/]];
|
||||||
|
let renderers = vec![(renderer1, &window1)/*, (renderer2, &window2)*/];
|
||||||
|
|
||||||
|
//creating pipeline
|
||||||
|
let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers);
|
||||||
|
|
||||||
|
//running controller
|
||||||
|
let mut controller = Controller::new(vec![subengine_pipeline]);
|
||||||
|
loop {
|
||||||
|
controller.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
//let engine_pipelines = vec![
|
||||||
|
// EnginePipeline {
|
||||||
|
// Inputs: vec![0,1],
|
||||||
|
// Engines: vec![&color_engine],
|
||||||
|
// Renderers: vec![(1,0)],
|
||||||
|
// },
|
||||||
|
// EnginePipeline {
|
||||||
|
// Inputs: vec![3],
|
||||||
|
// Engines: vec![&color_engine],
|
||||||
|
// Renderers: vec![(1,1),(1,2),(1,3)],
|
||||||
|
//}];
|
||||||
|
|
||||||
|
//let controller = Controller::new(renderers, &windows, &windows, engine_pipelines);
|
||||||
|
//controller.run();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
//let local_state = LocalState::default();
|
//let local_state = LocalState::default();
|
||||||
|
|
||||||
let color = [0.5, 0.0, 0.0, 1.0];
|
// let color = [0.5, 0.0, 0.0, 1.0];
|
||||||
|
//
|
||||||
loop {
|
// loop {
|
||||||
for window in &mut windows {
|
// for window in &mut windows {
|
||||||
match renderer.draw_clear_frame(window, color) {
|
// match renderer.draw_clear_frame(window, color) {
|
||||||
Err(err) => println!("{}", err),
|
// Err(err) => println!("{}", err),
|
||||||
_ => (),
|
// _ => (),
|
||||||
}}}
|
// }}}
|
||||||
|
//
|
||||||
// Ok(())
|
// Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +142,7 @@ pub fn run() -> Result<(), &'static str> {
|
|||||||
//
|
//
|
||||||
// let mut color = [0.0, 0.0, 0.0, 0.0];
|
// let mut color = [0.0, 0.0, 0.0, 0.0];
|
||||||
//
|
//
|
||||||
// loop {
|
// loop
|
||||||
//
|
//
|
||||||
// //TODO manage errors
|
// //TODO manage errors
|
||||||
// for window in windows {
|
// for window in windows {
|
||||||
|
|||||||
@ -4,6 +4,11 @@ use log::{debug, error, info, trace, warn};
|
|||||||
use std::{
|
use std::{
|
||||||
mem::ManuallyDrop,
|
mem::ManuallyDrop,
|
||||||
iter,
|
iter,
|
||||||
|
cell::RefCell,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
io::Output,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod gpu;
|
mod gpu;
|
||||||
@ -12,18 +17,11 @@ use gpu::Gpu;
|
|||||||
mod swap_system;
|
mod swap_system;
|
||||||
use swap_system::SwapSystem;
|
use swap_system::SwapSystem;
|
||||||
|
|
||||||
pub mod output;
|
|
||||||
use output::Output;
|
|
||||||
|
|
||||||
//mod pipeline;
|
|
||||||
//use pipeline::Pipeline;
|
|
||||||
|
|
||||||
//--Renderer implementation-------------------------------------------------------------------------
|
//--Renderer implementation-------------------------------------------------------------------------
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Renderer<B: gfx_hal::Backend> {
|
pub struct Renderer<B: gfx_hal::Backend> {
|
||||||
instance: ManuallyDrop<B::Instance>,
|
instance: ManuallyDrop<B::Instance>,
|
||||||
gpu: ManuallyDrop<Gpu<B>>,
|
gpu: ManuallyDrop<Gpu<B>>,
|
||||||
//pipelines: Vec<Pipeline<B>>,
|
|
||||||
swap_systems: Vec<SwapSystem<B>>,
|
swap_systems: Vec<SwapSystem<B>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,12 +60,11 @@ impl<B> Renderer<B>
|
|||||||
where
|
where
|
||||||
B: gfx_hal::Backend,
|
B: gfx_hal::Backend,
|
||||||
{
|
{
|
||||||
pub fn new<'a, H, T: 'a, I>(outputs: I) -> Result<Renderer<B>, &'static str>
|
pub fn new<'a, W: 'a, O: 'a, I>(outputs: &mut I) -> Result<Renderer<B>, &'static str>
|
||||||
where
|
where
|
||||||
H: raw_window_handle::HasRawWindowHandle,
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
T: Output<H>,
|
O: Output<W>,
|
||||||
I: IntoIterator<Item = &'a mut T>,
|
I: Iterator<Item = &'a RefCell<O>>,
|
||||||
|
|
||||||
{
|
{
|
||||||
use gfx_hal::Instance;
|
use gfx_hal::Instance;
|
||||||
|
|
||||||
@ -91,11 +88,11 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_clear_frame<T, O>(&mut self, output: &mut O, color: [f32; 4])
|
pub fn draw_clear_frame<W, O>(&mut self, output: &RefCell<O>, color: [f32; 4])
|
||||||
-> Result<(), &'static str>
|
-> Result<(), &'static str>
|
||||||
where
|
where
|
||||||
T: raw_window_handle::HasRawWindowHandle,
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
O: Output<T>
|
O: Output<W>,
|
||||||
{
|
{
|
||||||
use gfx_hal::{
|
use gfx_hal::{
|
||||||
window::AcquireError,
|
window::AcquireError,
|
||||||
@ -103,7 +100,7 @@ where
|
|||||||
queue::Submission,
|
queue::Submission,
|
||||||
};
|
};
|
||||||
|
|
||||||
let swap_system = &mut self.swap_systems[output.get_id()];
|
let swap_system = &mut self.swap_systems[output.borrow_mut().get_id()];
|
||||||
|
|
||||||
let mut frame = match swap_system.acquire_frame(&self.gpu) {
|
let mut frame = match swap_system.acquire_frame(&self.gpu) {
|
||||||
Ok(frame) => frame,
|
Ok(frame) => frame,
|
||||||
|
|||||||
@ -4,6 +4,7 @@ use log::{debug, error, info, trace, warn};
|
|||||||
use std::{
|
use std::{
|
||||||
mem::ManuallyDrop,
|
mem::ManuallyDrop,
|
||||||
ptr::read,
|
ptr::read,
|
||||||
|
cell::RefCell,
|
||||||
};
|
};
|
||||||
|
|
||||||
use gfx_hal::{
|
use gfx_hal::{
|
||||||
@ -13,9 +14,14 @@ use gfx_hal::{
|
|||||||
|
|
||||||
use gfx_hal::adapter::Gpu as GfxGpu;
|
use gfx_hal::adapter::Gpu as GfxGpu;
|
||||||
|
|
||||||
use super::output::Output;
|
use crate::io::Output;
|
||||||
|
|
||||||
//--Gpu implementation------------------------------------------------------------------------------
|
//--Gpu implementation------------------------------------------------------------------------------
|
||||||
|
/// A struct managing all things related to a specific GPU
|
||||||
|
///
|
||||||
|
/// The `GPU` struct manages the structs from the gfx_hal[gfx_hal] related to the physical device.
|
||||||
|
/// It implements constructor and destructors as well as acces functions. This is done to make the
|
||||||
|
/// usage of the HAL easier and make the higher level code less dependant on changes in it.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Gpu<B: gfx_hal::Backend> {
|
pub struct Gpu<B: gfx_hal::Backend> {
|
||||||
adapter: ManuallyDrop<Adapter<B>>,
|
adapter: ManuallyDrop<Adapter<B>>,
|
||||||
@ -47,12 +53,13 @@ impl<B> Gpu<B>
|
|||||||
where
|
where
|
||||||
B: gfx_hal::Backend,
|
B: gfx_hal::Backend,
|
||||||
{
|
{
|
||||||
pub fn new<'a, H, T: 'a, I>(instance: &B::Instance, outputs: I)
|
/// Create a new `GPU` based on an `instance` of the gfx_hal[gfx_hal].
|
||||||
|
pub fn new<'a, W, O: 'a, I>(instance: &B::Instance, outputs: &mut I)
|
||||||
-> Result<(Gpu<B>, Vec<B::Surface>), &'static str>
|
-> Result<(Gpu<B>, Vec<B::Surface>), &'static str>
|
||||||
where
|
where
|
||||||
H: raw_window_handle::HasRawWindowHandle,
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
T: Output<H>,
|
O: Output<W>,
|
||||||
I: IntoIterator<Item = &'a mut T>,
|
I: Iterator<Item = &'a RefCell<O>>,
|
||||||
{
|
{
|
||||||
use gfx_hal::{
|
use gfx_hal::{
|
||||||
queue::family::QueueFamily,
|
queue::family::QueueFamily,
|
||||||
@ -65,13 +72,13 @@ where
|
|||||||
|
|
||||||
let mut id = 0;
|
let mut id = 0;
|
||||||
outputs
|
outputs
|
||||||
.into_iter()
|
.by_ref()
|
||||||
.map(|output| unsafe {
|
.map(|output| unsafe {
|
||||||
output.set_id(id);
|
output.borrow_mut().set_id(id);
|
||||||
id += 1;
|
id += 1;
|
||||||
|
|
||||||
instance
|
instance
|
||||||
.create_surface(output.window())
|
.create_surface(output.borrow().window())
|
||||||
.map_err(|_| "Could not create surface")
|
.map_err(|_| "Could not create surface")
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, &str>>()?
|
.collect::<Result<Vec<_>, &str>>()?
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
#[allow(unused_imports)]
|
|
||||||
use log::{debug, error, info, trace, warn};
|
|
||||||
|
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
|
||||||
|
|
||||||
use crate::utils::Rect;
|
|
||||||
|
|
||||||
//--Output trait------------------------------------------------------------------------------------
|
|
||||||
pub trait Output<T>
|
|
||||||
where
|
|
||||||
T: HasRawWindowHandle,
|
|
||||||
{
|
|
||||||
fn get_id(&self) -> usize;
|
|
||||||
fn set_id(&mut self, id: usize);
|
|
||||||
|
|
||||||
fn size(&mut self) -> &mut Rect<i32>;
|
|
||||||
|
|
||||||
fn window(&self) -> &T;
|
|
||||||
}
|
|
||||||
|
|
||||||
//impl<'a, T, O> Output<T> for &'a O
|
|
||||||
//where
|
|
||||||
// T: HasRawWindowHandle,
|
|
||||||
// O: Output<T> {
|
|
||||||
// fn id(&mut self) -> &mut i32 { Output::id(*self) }
|
|
||||||
//
|
|
||||||
// fn size(&mut self) -> &mut Rect<i32> { Output::size(*self) }
|
|
||||||
//
|
|
||||||
// fn window(&self) -> &T { Output::window(*self) }
|
|
||||||
//}
|
|
||||||
|
|
||||||
impl<'a, T, O> Output<T> for &'a mut O
|
|
||||||
where
|
|
||||||
T: HasRawWindowHandle,
|
|
||||||
O: Output<T> {
|
|
||||||
fn get_id(&self) -> usize { Output::get_id(*self) }
|
|
||||||
fn set_id(&mut self, id: usize) { Output::set_id(*self, id); }
|
|
||||||
|
|
||||||
fn size(&mut self) -> &mut Rect<i32> { Output::size(*self) }
|
|
||||||
|
|
||||||
fn window(&self) -> &T { Output::window(*self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
22
src/subengine.rs
Normal file
22
src/subengine.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
pub mod subengine_controller;
|
||||||
|
pub use self::subengine_controller::SubengineController;
|
||||||
|
|
||||||
|
pub mod subengine_pipeline;
|
||||||
|
pub use self::subengine_pipeline::SubenginePipeline;
|
||||||
|
|
||||||
|
pub mod test_subengine;
|
||||||
|
pub use self::test_subengine::TestSubengine;
|
||||||
|
|
||||||
|
|
||||||
|
//--SubEngine trait------------------------------------------------------------------------------------
|
||||||
|
/// A trait that should be implemented by all subengines running it the game engine.
|
||||||
|
///
|
||||||
|
/// Allow the [`Controller`] to run custom subengines.
|
||||||
|
pub trait Subengine {
|
||||||
|
/// Main function of the subengine. Called byt the [`Controller`] for each frame.
|
||||||
|
fn run(&self);
|
||||||
|
}
|
||||||
|
|
||||||
140
src/subengine/subengine_controller.rs
Normal file
140
src/subengine/subengine_controller.rs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
sync::mpsc::{Sender, Receiver},
|
||||||
|
thread::JoinHandle,
|
||||||
|
mem::ManuallyDrop,
|
||||||
|
ptr::read,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::subengine::Subengine;
|
||||||
|
|
||||||
|
//--SubengineController Implementation--------------------------------------------------------------
|
||||||
|
/// Handle to manage an [`Subengine`].
|
||||||
|
///
|
||||||
|
/// The `SubengineController` runs the [`Engine`] in a separated thread with some control code to
|
||||||
|
/// allow control from the main thread. SubengineControllers are used by the [`Controller`] to
|
||||||
|
/// interact with Subengines.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SubengineController {
|
||||||
|
tx: Sender<SubengineCommand>,
|
||||||
|
rx: Receiver<SubengineResponse>,
|
||||||
|
handle: ManuallyDrop<JoinHandle<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SubengineController {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.exec(SubengineCommand::Stop);
|
||||||
|
unsafe { let _ = ManuallyDrop::into_inner(read(&mut self.handle)).join(); }
|
||||||
|
debug!("SubengineController dropped !");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubengineController {
|
||||||
|
/// Creates a new `SubengineController` from a given [`Engine`]. Since the latter will be moved
|
||||||
|
/// to a separated thread, it must implement the [`Send`] trait.
|
||||||
|
pub fn new<E: 'static>(engine: E) -> SubengineController
|
||||||
|
where
|
||||||
|
E: Subengine + std::marker::Send,
|
||||||
|
{
|
||||||
|
use std::{
|
||||||
|
thread,
|
||||||
|
sync::mpsc::channel,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Creating SubengineController...");
|
||||||
|
let (tx, e_rx) = channel();
|
||||||
|
let (e_tx, rx) = channel();
|
||||||
|
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
trace!("Subengine thread started !");
|
||||||
|
loop {
|
||||||
|
//TODO manage errors
|
||||||
|
match e_rx.recv().unwrap() {
|
||||||
|
SubengineCommand::Run => engine.run(),
|
||||||
|
SubengineCommand::Stop => return,
|
||||||
|
};
|
||||||
|
e_tx.send(SubengineResponse::Done).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SubengineController {
|
||||||
|
tx,
|
||||||
|
rx,
|
||||||
|
handle: ManuallyDrop::new(handle),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a command to the [`Subengine`]. This is function is not blocking and WILL NOT check if
|
||||||
|
/// the command was received.
|
||||||
|
pub fn exec(&self, cmd: SubengineCommand) {
|
||||||
|
self.tx.send(cmd).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blocking function, waits for the [`Subengine`] to finish executing the last command given.
|
||||||
|
pub fn wait_for_exec(&self, timeout: Duration) -> Result<(),SubengineWaitError> {
|
||||||
|
match self.rx.recv_timeout(timeout) {
|
||||||
|
Err(_) => Err(SubengineWaitError::NoResponse),
|
||||||
|
Ok(val) => match val {
|
||||||
|
SubengineResponse::Done => Ok(()),
|
||||||
|
//_ => Err(SubengineWaitError::BadResponse),
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--SubengineCommand enum---------------------------------------------------------------------------
|
||||||
|
/// Commands that can be sent to an [`Subengine`] via an `EngineController`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SubengineCommand {
|
||||||
|
Run,
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
//--SubengineWaitError enum-------------------------------------------------------------------------
|
||||||
|
/// Errors that can be returned by the wait_for_exec function.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SubengineWaitError {
|
||||||
|
NoResponse,
|
||||||
|
BadResponse,
|
||||||
|
}
|
||||||
|
|
||||||
|
//--SubengineResponse enum--------------------------------------------------------------------------
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum SubengineResponse {
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
//--Tests-------------------------------------------------------------------------------------------
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::subengine::TestSubengine;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new_drop() {
|
||||||
|
let (test_subengine, _test_rx) = TestSubengine::new("run");
|
||||||
|
let subengine_controller = SubengineController::new(test_subengine);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exec() {
|
||||||
|
let (test_subengine, test_rx) = TestSubengine::new("run");
|
||||||
|
let subengine_controller = SubengineController::new(test_subengine);
|
||||||
|
|
||||||
|
subengine_controller.exec(SubengineCommand::Run);
|
||||||
|
let response = test_rx.recv_timeout(Duration::from_millis(10)).unwrap();
|
||||||
|
assert_eq!(response, "run");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wait_for_exec() {
|
||||||
|
let (test_subengine, _test_rx) = TestSubengine::new("run");
|
||||||
|
let subengine_controller = SubengineController::new(test_subengine);
|
||||||
|
|
||||||
|
subengine_controller.exec(SubengineCommand::Run);
|
||||||
|
subengine_controller.wait_for_exec(Duration::from_millis(10)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
72
src/subengine/subengine_pipeline.rs
Normal file
72
src/subengine/subengine_pipeline.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
use gfx_backend_vulkan as vk_back;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
io::{Input, Output},
|
||||||
|
subengine::SubengineController,
|
||||||
|
renderer::Renderer,
|
||||||
|
};
|
||||||
|
|
||||||
|
//--SubenginePipeline Implementation----------------------------------------------------------------
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SubenginePipeline<'a, I, W, O>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
|
O: Output<W>,
|
||||||
|
{
|
||||||
|
pub inputs: Vec<&'a RefCell<I>>,
|
||||||
|
pub subengines: Vec<Vec<SubengineController>>,
|
||||||
|
pub renderers: Vec<(Renderer<vk_back::Backend>, &'a RefCell<O>)>,
|
||||||
|
pub phantom: PhantomData<W>, //needed because of compiler limitations
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, W, O> SubenginePipeline<'a, I, W, O>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
W: raw_window_handle::HasRawWindowHandle,
|
||||||
|
O: Output<W>,
|
||||||
|
{
|
||||||
|
|
||||||
|
pub fn new<Ii, Is, Iss, Ir>(inputs: Ii, subengines: Is, renderers: Ir)
|
||||||
|
-> SubenginePipeline<'a, I, W, O>
|
||||||
|
where
|
||||||
|
Ii: IntoIterator<Item = &'a RefCell<I>>,
|
||||||
|
Iss: IntoIterator<Item = SubengineController>,
|
||||||
|
Is: IntoIterator<Item = Iss>,
|
||||||
|
Ir: IntoIterator<Item = (Renderer<vk_back::Backend>, &'a RefCell<O>)>,
|
||||||
|
{
|
||||||
|
let inputs_vec = inputs
|
||||||
|
.into_iter()
|
||||||
|
.map(|input| input)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let subengines_vecs = subengines
|
||||||
|
.into_iter()
|
||||||
|
.map(|subengines_vec| subengines_vec
|
||||||
|
.into_iter()
|
||||||
|
.map(|subengine| subengine)
|
||||||
|
.collect())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let renderers_vec = renderers
|
||||||
|
.into_iter()
|
||||||
|
.map(|renderer| renderer)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
SubenginePipeline{
|
||||||
|
inputs: inputs_vec,
|
||||||
|
subengines: subengines_vecs,
|
||||||
|
renderers: renderers_vec,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
36
src/subengine/test_subengine.rs
Normal file
36
src/subengine/test_subengine.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#[allow(unused_imports)]
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use std::sync::mpsc::{Sender, Receiver, channel};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
//--TestSubengine Implementation--------------------------------------------------------------------
|
||||||
|
/// [`Subengine`] implementation used for tests.
|
||||||
|
///
|
||||||
|
/// Simply sends back the given [`str`] depending on the command.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TestSubengine {
|
||||||
|
tx: Sender<&'static str>,
|
||||||
|
run: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSubengine {
|
||||||
|
/// Creates a `TestSubengine` with specific [`str`]s to use.
|
||||||
|
pub fn new(run: &'static str)
|
||||||
|
-> (TestSubengine, Receiver<&'static str>) {
|
||||||
|
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
(
|
||||||
|
TestSubengine { tx, run },
|
||||||
|
rx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Subengine for TestSubengine {
|
||||||
|
fn run(&self) {
|
||||||
|
self.tx.send(self.run).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,6 +1,11 @@
|
|||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
thread,
|
||||||
|
sync::mpsc,
|
||||||
|
};
|
||||||
|
|
||||||
use winit::{
|
use winit::{
|
||||||
dpi::PhysicalSize,
|
dpi::PhysicalSize,
|
||||||
event_loop::{EventLoop},
|
event_loop::{EventLoop},
|
||||||
@ -8,8 +13,10 @@ use winit::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
//TODO fix that
|
//TODO fix that
|
||||||
use super::renderer::output::Output;
|
use crate::{
|
||||||
use crate::utils::Rect;
|
io::{Output, Input, Key, ReadError},
|
||||||
|
utils::Rect,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WinitWindow {
|
pub struct WinitWindow {
|
||||||
@ -17,27 +24,77 @@ pub struct WinitWindow {
|
|||||||
size: Rect<i32>,
|
size: Rect<i32>,
|
||||||
id: usize,
|
id: usize,
|
||||||
|
|
||||||
pub event_loop: EventLoop<()>,
|
handle: thread::JoinHandle<()>,
|
||||||
|
receiver: mpsc::Receiver<Key>,
|
||||||
window: Window,
|
window: Window,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WinitWindow {
|
impl WinitWindow {
|
||||||
pub fn new(title: &str, size: Rect<i32>) -> Result<WinitWindow, &'static str> {
|
pub fn new(title: &str, size: Rect<i32>) -> Result<WinitWindow, &'static str> {
|
||||||
|
use winit::platform::unix::EventLoopExtUnix;
|
||||||
|
|
||||||
|
debug!("Creating window");
|
||||||
let name = title.to_string();
|
let name = title.to_string();
|
||||||
let id = 0;
|
let id = 0;
|
||||||
let event_loop = EventLoop::new();
|
|
||||||
let window = WindowBuilder::new()
|
//Since we can't move the EventLoop from one thread to another, we need to create it in the
|
||||||
.with_inner_size(PhysicalSize {width: size.w, height: size.h})
|
//right thread and then move the Window back to the main thread instead
|
||||||
.with_title(title)
|
let cloned_name = name.clone();
|
||||||
.build(&event_loop)
|
let (tx, rx) = mpsc::channel();
|
||||||
.map_err(|_| "Could not create window")?;
|
let (tmp_tx, tmp_rx) = mpsc::sync_channel(1);
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
|
||||||
|
trace!("Creating Window in EventLoop thread");
|
||||||
|
//winit doesn't like use creating the EventLoop in another thread either so we have to
|
||||||
|
//drop crossplatform compatibility :/
|
||||||
|
let event_loop = EventLoop::new_any_thread();
|
||||||
|
let window = WindowBuilder::new()
|
||||||
|
.with_inner_size(PhysicalSize {width: size.w, height: size.h})
|
||||||
|
.with_title(cloned_name)
|
||||||
|
.build(&event_loop).unwrap();
|
||||||
|
|
||||||
|
trace!("Sending Window back to main thread");
|
||||||
|
tmp_tx.send(window).unwrap();
|
||||||
|
|
||||||
|
//TODO clean event type
|
||||||
|
event_loop.run(move |event: winit::event::Event<'_, ()>, _, control_flow| {
|
||||||
|
use winit::{
|
||||||
|
event_loop::ControlFlow,
|
||||||
|
event::Event,
|
||||||
|
event,
|
||||||
|
};
|
||||||
|
|
||||||
|
*control_flow = ControlFlow::Wait;
|
||||||
|
|
||||||
|
//TODO manage errors
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent{window_id: _, event} => match event {
|
||||||
|
event::WindowEvent::CloseRequested => {
|
||||||
|
tx.send(Key::Close).unwrap();
|
||||||
|
warn!("Stop input thread");
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
},
|
||||||
|
event::WindowEvent::CursorMoved{position, ..} => {
|
||||||
|
tx.send(Key::MouseMove{
|
||||||
|
x: position.x,
|
||||||
|
y: position.y,
|
||||||
|
}).unwrap();
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}})
|
||||||
|
});
|
||||||
|
|
||||||
|
let window = tmp_rx.recv().unwrap();
|
||||||
|
trace!("Received Window in main thread");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
size,
|
size,
|
||||||
id,
|
id,
|
||||||
event_loop,
|
handle: handle,
|
||||||
|
receiver: rx,
|
||||||
window,
|
window,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -52,3 +109,14 @@ impl Output<Window> for WinitWindow {
|
|||||||
fn window(&self) -> &Window { &self.window }
|
fn window(&self) -> &Window { &self.window }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Input for WinitWindow {
|
||||||
|
fn read(&self, timeout_ms: u32) -> Result<Key, ReadError> {
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
match self.receiver.recv_timeout(Duration::from_millis(timeout_ms.into())) {
|
||||||
|
Ok(key) => Ok(key),
|
||||||
|
Err(_) => Err(ReadError::Timeout),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user