engine: get a window showing and things rendered
This commit is contained in:
parent
45fd190409
commit
8b1077cab7
|
@ -80,24 +80,22 @@ async fn main() {
|
||||||
)
|
)
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
let world = app.world_mut();
|
//let world = app.world;
|
||||||
world.add_resource(action_handler);
|
app.add_resource(action_handler);
|
||||||
app.with_plugin(InputActionPlugin);
|
app.with_plugin(InputActionPlugin);
|
||||||
};
|
};
|
||||||
|
|
||||||
App::initialize()
|
let mut a = App::new();
|
||||||
.await
|
a.with_plugin(lyra_engine::DefaultPlugins)
|
||||||
.with_plugin(lyra_engine::DefaultPlugins)
|
|
||||||
.with_plugin(setup_scene_plugin)
|
.with_plugin(setup_scene_plugin)
|
||||||
.with_plugin(action_handler_plugin)
|
.with_plugin(action_handler_plugin)
|
||||||
//.with_plugin(camera_debug_plugin)
|
//.with_plugin(camera_debug_plugin)
|
||||||
.with_plugin(FreeFlyCameraPlugin)
|
.with_plugin(FreeFlyCameraPlugin);
|
||||||
.run()
|
a.run();
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_scene_plugin(app: &mut App) {
|
fn setup_scene_plugin(app: &mut App) {
|
||||||
let world = game.world_mut();
|
let world = &mut app.world;
|
||||||
let resman = world.get_resource_mut::<ResourceManager>();
|
let resman = world.get_resource_mut::<ResourceManager>();
|
||||||
|
|
||||||
/* let camera_gltf = resman
|
/* let camera_gltf = resman
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use std::{cell::OnceCell, collections::VecDeque, ptr::NonNull, sync::Arc};
|
use std::{cell::OnceCell, collections::VecDeque, ptr::NonNull, sync::Arc};
|
||||||
|
|
||||||
|
use async_std::task::block_on;
|
||||||
use lyra_ecs::{system::{IntoSystem, System}, ResourceObject, World};
|
use lyra_ecs::{system::{IntoSystem, System}, ResourceObject, World};
|
||||||
use lyra_math::{IVec2, Vec2};
|
use lyra_math::{IVec2, Vec2};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use tracing::{debug, debug_span, info, Level};
|
use tracing::{debug, debug_span, info, warn, error, Level};
|
||||||
use tracing_appender::non_blocking;
|
use tracing_appender::non_blocking;
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
layer::SubscriberExt,
|
layer::SubscriberExt,
|
||||||
|
@ -13,7 +14,7 @@ use tracing_subscriber::{
|
||||||
|
|
||||||
use winit::{application::ApplicationHandler, event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, keyboard::{Key, NamedKey}, window::{Window, WindowId}};
|
use winit::{application::ApplicationHandler, event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, keyboard::{Key, NamedKey}, window::{Window, WindowId}};
|
||||||
|
|
||||||
use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input::InputEvent, plugin::Plugin, change_tracker::Ct, EventQueue, StagedExecutor, Stage};
|
use crate::{change_tracker::Ct, input::InputEvent, plugin::Plugin, render::{renderer::{BasicRenderer, Renderer}, window::{PrimaryWindow, WindowOptions}}, winit::WinitWindows, EventQueue, Stage, StagedExecutor};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, Debug)]
|
#[derive(Clone, Copy, Hash, Debug)]
|
||||||
pub enum GameStages {
|
pub enum GameStages {
|
||||||
|
@ -64,17 +65,56 @@ pub struct App {
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
// init logging
|
||||||
|
let (stdout_layer, stdout_nb) = non_blocking(std::io::stdout());
|
||||||
|
{
|
||||||
|
let t = tracing_subscriber::registry()
|
||||||
|
.with(fmt::layer().with_writer(stdout_layer));
|
||||||
|
|
||||||
|
#[cfg(feature = "tracy")]
|
||||||
|
let t = t.with(tracing_tracy::TracyLayer::default());
|
||||||
|
|
||||||
|
t.with(filter::Targets::new()
|
||||||
|
// done by prefix, so it includes all lyra subpackages
|
||||||
|
.with_target("lyra", Level::DEBUG)
|
||||||
|
.with_target("wgsl_preprocessor", Level::DEBUG)
|
||||||
|
.with_target("wgpu", Level::WARN)
|
||||||
|
.with_target("winit", Level::DEBUG)
|
||||||
|
.with_default(Level::INFO))
|
||||||
|
.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the logger worker guard to ensure logging still happens
|
||||||
|
let mut world = World::new();
|
||||||
|
world.add_resource(stdout_nb);
|
||||||
|
|
||||||
|
// initialize ecs system stages
|
||||||
|
let mut staged = StagedExecutor::new();
|
||||||
|
staged.add_stage(GameStages::First);
|
||||||
|
staged.add_stage_after(GameStages::First, GameStages::PreUpdate);
|
||||||
|
staged.add_stage_after(GameStages::PreUpdate, GameStages::Update);
|
||||||
|
staged.add_stage_after(GameStages::Update, GameStages::PostUpdate);
|
||||||
|
staged.add_stage_after(GameStages::PostUpdate, GameStages::Last);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
windows: FxHashMap::default(),
|
windows: FxHashMap::default(),
|
||||||
renderer: OnceCell::new(),
|
renderer: OnceCell::new(),
|
||||||
world: World::new(),
|
world,
|
||||||
plugins: Default::default(),
|
plugins: Default::default(),
|
||||||
startup_systems: Default::default(),
|
startup_systems: Default::default(),
|
||||||
staged_exec: StagedExecutor::new(),
|
staged_exec: staged,
|
||||||
run_fn: OnceCell::new(),
|
run_fn: OnceCell::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self) {
|
||||||
|
let wptr = NonNull::from(&self.world);
|
||||||
|
|
||||||
|
if let Err(e) = self.staged_exec.execute(wptr, true) {
|
||||||
|
error!("Error when executing staged systems: '{}'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
||||||
self.renderer.get_mut()
|
self.renderer.get_mut()
|
||||||
.expect("renderer was not initialized")
|
.expect("renderer was not initialized")
|
||||||
|
@ -167,7 +207,7 @@ impl App {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_run_fn<F>(&self, f: F)
|
pub fn set_run_fn<F>(&self, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(App) + 'static
|
F: FnOnce(App) + 'static
|
||||||
{
|
{
|
||||||
|
@ -175,7 +215,7 @@ impl App {
|
||||||
let _ = self.run_fn.set(Box::new(f));
|
let _ = self.run_fn.set(Box::new(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(mut self) {
|
pub fn run(mut self) {
|
||||||
let f = self.run_fn.take()
|
let f = self.run_fn.take()
|
||||||
.expect("No run function set");
|
.expect("No run function set");
|
||||||
f(self);
|
f(self);
|
||||||
|
@ -183,8 +223,46 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for App {
|
impl ApplicationHandler for App {
|
||||||
|
fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
|
debug!("update now");
|
||||||
|
|
||||||
|
self.update();
|
||||||
|
|
||||||
|
let renderer = self.renderer.get_mut().expect("renderer was not initialized");
|
||||||
|
renderer.prepare(&mut self.world);
|
||||||
|
|
||||||
|
if let Some(mut event_queue) = self.world.try_get_resource_mut::<EventQueue>() {
|
||||||
|
event_queue.update_events();
|
||||||
|
}
|
||||||
|
|
||||||
|
match renderer.render() {
|
||||||
|
Ok(_) => {}
|
||||||
|
// Reconfigure the surface if lost
|
||||||
|
//Err(wgpu::SurfaceError::Lost) => self.on_resize(.surface_size()),
|
||||||
|
// The system is out of memory, we should probably quit
|
||||||
|
Err(wgpu::SurfaceError::OutOfMemory) => {
|
||||||
|
error!("OOM");
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
// All other errors (Outdated, Timeout) should be resolved by the next frame
|
||||||
|
Err(e) => eprintln!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
debug!("Resumed");
|
let world = &mut self.world;
|
||||||
|
let en = world.spawn((WindowOptions::default(), PrimaryWindow));
|
||||||
|
|
||||||
|
let attr = Window::default_attributes();
|
||||||
|
let mut windows = world.get_resource_mut::<WinitWindows>();
|
||||||
|
let wid = windows.create_window(event_loop, en, attr).unwrap();
|
||||||
|
let window = windows.windows.get(&wid).unwrap().clone();
|
||||||
|
drop(windows);
|
||||||
|
|
||||||
|
let renderer = block_on(BasicRenderer::create_with_window(world, window));
|
||||||
|
if self.renderer.set(Box::new(renderer)).is_err() {
|
||||||
|
warn!("renderer was re-initialized");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
|
@ -194,10 +272,12 @@ impl ApplicationHandler for App {
|
||||||
event: WindowEvent,
|
event: WindowEvent,
|
||||||
) {
|
) {
|
||||||
//let _e = debug_span!("window_event", window=window_id).entered();
|
//let _e = debug_span!("window_event", window=window_id).entered();
|
||||||
let window = match self.windows.get_mut(&window_id) {
|
let windows = self.world.get_resource::<WinitWindows>();
|
||||||
Some(w) => w,
|
let window = match windows.windows.get(&window_id) {
|
||||||
|
Some(w) => w.clone(),
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
drop(windows);
|
||||||
|
|
||||||
// If try_from failed, that means that the WindowEvent is not an
|
// If try_from failed, that means that the WindowEvent is not an
|
||||||
// input related event.
|
// input related event.
|
||||||
|
@ -230,7 +310,7 @@ impl ApplicationHandler for App {
|
||||||
let mut state = self.world.get_resource_or_else(WindowState::new);
|
let mut state = self.world.get_resource_or_else(WindowState::new);
|
||||||
state.focused = focused;
|
state.focused = focused;
|
||||||
},
|
},
|
||||||
WindowEvent::ModifiersChanged(modifiers) => todo!(),
|
WindowEvent::ModifiersChanged(modifiers) => debug!("modifiers changed: {:?}", modifiers),
|
||||||
WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer } => {
|
WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer } => {
|
||||||
info!("changed scale to {scale_factor}");
|
info!("changed scale to {scale_factor}");
|
||||||
},
|
},
|
||||||
|
@ -239,7 +319,9 @@ impl ApplicationHandler for App {
|
||||||
let mut state = self.world.get_resource_or_else(WindowState::new);
|
let mut state = self.world.get_resource_or_else(WindowState::new);
|
||||||
state.occluded = occ;
|
state.occluded = occ;
|
||||||
},
|
},
|
||||||
WindowEvent::RedrawRequested => todo!(),
|
WindowEvent::RedrawRequested => {
|
||||||
|
debug!("should redraw");
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub mod game;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod winit;
|
||||||
pub mod as_any;
|
pub mod as_any;
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
pub mod change_tracker;
|
pub mod change_tracker;
|
||||||
|
|
|
@ -8,6 +8,7 @@ use lyra_ecs::CommandQueue;
|
||||||
use lyra_resource::ResourceManager;
|
use lyra_resource::ResourceManager;
|
||||||
|
|
||||||
use crate::game::App;
|
use crate::game::App;
|
||||||
|
use crate::winit::WinitPlugin;
|
||||||
use crate::EventsPlugin;
|
use crate::EventsPlugin;
|
||||||
use crate::DeltaTimePlugin;
|
use crate::DeltaTimePlugin;
|
||||||
use crate::input::InputPlugin;
|
use crate::input::InputPlugin;
|
||||||
|
@ -19,15 +20,16 @@ pub trait Plugin {
|
||||||
fn setup(&self, app: &mut App);
|
fn setup(&self, app: &mut App);
|
||||||
|
|
||||||
fn is_ready(&self, app: &mut App) -> bool {
|
fn is_ready(&self, app: &mut App) -> bool {
|
||||||
|
let _ = app;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete(&self, _app: &mut App) {
|
fn complete(&self, app: &mut App) {
|
||||||
|
let _ = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup(&self, _app: &mut App) {
|
fn cleanup(&self, app: &mut App) {
|
||||||
|
let _ = app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +129,7 @@ pub struct DefaultPlugins;
|
||||||
|
|
||||||
impl Plugin for DefaultPlugins {
|
impl Plugin for DefaultPlugins {
|
||||||
fn setup(&self, app: &mut App) {
|
fn setup(&self, app: &mut App) {
|
||||||
|
WinitPlugin.setup(app);
|
||||||
CommandQueuePlugin.setup(app);
|
CommandQueuePlugin.setup(app);
|
||||||
EventsPlugin.setup(app);
|
EventsPlugin.setup(app);
|
||||||
InputPlugin.setup(app);
|
InputPlugin.setup(app);
|
||||||
|
|
|
@ -5,9 +5,9 @@ const LIGHT_TY_DIRECTIONAL = 0u;
|
||||||
const LIGHT_TY_POINT = 1u;
|
const LIGHT_TY_POINT = 1u;
|
||||||
const LIGHT_TY_SPOT = 2u;
|
const LIGHT_TY_SPOT = 2u;
|
||||||
|
|
||||||
type vec2f = vec2<f32>;
|
alias vec2f = vec2<f32>;
|
||||||
type vec3f = vec3<f32>;
|
alias vec3f = vec3<f32>;
|
||||||
type vec4f = vec4<f32>;
|
alias vec4f = vec4<f32>;
|
||||||
|
|
||||||
struct CameraUniform {
|
struct CameraUniform {
|
||||||
view: mat4x4<f32>,
|
view: mat4x4<f32>,
|
||||||
|
@ -317,8 +317,8 @@ fn cone_inside_plane(cone: Cone, plane: Plane) -> bool {
|
||||||
return point_inside_plane(cone.tip, plane) && point_inside_plane(furthest, plane);
|
return point_inside_plane(cone.tip, plane) && point_inside_plane(furthest, plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cone_inside_frustum(cone: Cone, frustum: array<Plane, 6>) -> bool {
|
fn cone_inside_frustum(cone: Cone, frustum_in: array<Plane, 6>) -> bool {
|
||||||
var frustum = frustum;
|
var frustum = frustum_in;
|
||||||
for (var i = 0u; i < 4u; i++) {
|
for (var i = 0u; i < 4u; i++) {
|
||||||
// TODO: better cone checking
|
// TODO: better cone checking
|
||||||
if (sphere_inside_plane(cone.tip, cone.radius, frustum[i])) {
|
if (sphere_inside_plane(cone.tip, cone.radius, frustum[i])) {
|
||||||
|
|
|
@ -1,28 +1,15 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use glam::{IVec2, Vec2};
|
use glam::{IVec2, Vec2};
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::{query::{Entities, ResMut, TickOf}, Component, World};
|
||||||
use tracing::{error, warn};
|
use tracing::{error, warn};
|
||||||
use winit::{
|
use winit::{
|
||||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition},
|
dpi::{LogicalPosition, LogicalSize, PhysicalPosition}, error::ExternalError, monitor::VideoModeHandle, window::{Fullscreen, Window}
|
||||||
error::ExternalError,
|
|
||||||
window::{Fullscreen, Window},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel};
|
pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel};
|
||||||
|
|
||||||
use crate::{change_tracker::Ct, input::InputEvent, plugin::Plugin, EventQueue};
|
use crate::{change_tracker::Ct, input::InputEvent, plugin::Plugin, winit::WinitWindows, EventQueue};
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
|
||||||
pub enum WindowMode {
|
|
||||||
/// The window will use the full size of the screen.
|
|
||||||
Fullscreen,
|
|
||||||
/// The window will be fullscreen with the full size of the screen without a border.
|
|
||||||
Borderless,
|
|
||||||
/// The window will not be fullscreen and will use the windows resolution size.
|
|
||||||
#[default]
|
|
||||||
Windowed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Clone, Copy)]
|
||||||
pub struct Area {
|
pub struct Area {
|
||||||
|
@ -93,8 +80,12 @@ impl Position {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Flag component that
|
||||||
|
#[derive(Clone, Component)]
|
||||||
|
pub struct PrimaryWindow;
|
||||||
|
|
||||||
/// Options that the window will be created with.
|
/// Options that the window will be created with.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Component)]
|
||||||
pub struct WindowOptions {
|
pub struct WindowOptions {
|
||||||
/// Prevents the window contents from being captured by other apps.
|
/// Prevents the window contents from being captured by other apps.
|
||||||
///
|
///
|
||||||
|
@ -136,6 +127,37 @@ pub struct WindowOptions {
|
||||||
/// * iOS / Android / Orbital: Unsupported.
|
/// * iOS / Android / Orbital: Unsupported.
|
||||||
pub cursor_visible: bool,
|
pub cursor_visible: bool,
|
||||||
|
|
||||||
|
/// The window’s current visibility state.
|
||||||
|
///
|
||||||
|
/// Platform-specific
|
||||||
|
/// * **X11:** Not implemented.
|
||||||
|
/// * **Wayland / iOS / Android / Web:** Unsupported.
|
||||||
|
pub visible: bool,
|
||||||
|
|
||||||
|
/// The window's transparency state.
|
||||||
|
///
|
||||||
|
/// This is just a hint that may not change anything about the window transparency, however
|
||||||
|
/// doing a mismatch between the content of your window and this hint may result in visual
|
||||||
|
/// artifacts.
|
||||||
|
///
|
||||||
|
/// The default value follows the [`winit::window::WindowAttributes::with_transparent`].
|
||||||
|
///
|
||||||
|
/// Platform-specific
|
||||||
|
/// * **macOS:** This will reset the window’s background color.
|
||||||
|
/// * **Web / iOS / Android:** Unsupported.
|
||||||
|
/// * **X11:** Can only be set while building the window, with
|
||||||
|
/// [`winit::window::WindowAttributes::with_transparent`].
|
||||||
|
pub transparent: bool,
|
||||||
|
|
||||||
|
/// The current blur state of the window
|
||||||
|
///
|
||||||
|
/// If `true`, this will make the transparent window background blurry.
|
||||||
|
///
|
||||||
|
/// Platform-specific
|
||||||
|
/// * **Android / iOS / X11 / Web / Windows:** Unsupported.
|
||||||
|
/// * **Wayland:** Only works with org_kde_kwin_blur_manager protocol.
|
||||||
|
pub blur: bool,
|
||||||
|
|
||||||
/// Turn window decorations on or off.
|
/// Turn window decorations on or off.
|
||||||
/// Enable/disable window decorations provided by the server or Winit. By default this is enabled.
|
/// Enable/disable window decorations provided by the server or Winit. By default this is enabled.
|
||||||
///
|
///
|
||||||
|
@ -150,8 +172,10 @@ pub struct WindowOptions {
|
||||||
/// * Web / iOS / Android: Unsupported.
|
/// * Web / iOS / Android: Unsupported.
|
||||||
pub enabled_buttons: WindowButtons,
|
pub enabled_buttons: WindowButtons,
|
||||||
|
|
||||||
/// The window mode. Can be used to set fullscreen and borderless.
|
/// The fullscreen settings for the monitor.
|
||||||
pub mode: WindowMode,
|
///
|
||||||
|
/// Set to `None` for windowed.
|
||||||
|
pub fullscreen: Option<Fullscreen>,
|
||||||
|
|
||||||
/// Sets whether the window should get IME events.
|
/// Sets whether the window should get IME events.
|
||||||
///
|
///
|
||||||
|
@ -199,6 +223,31 @@ pub struct WindowOptions {
|
||||||
/// * iOS / Android / Web / Orbital: Unsupported.
|
/// * iOS / Android / Web / Orbital: Unsupported.
|
||||||
pub min_inner_size: Option<Size>,
|
pub min_inner_size: Option<Size>,
|
||||||
|
|
||||||
|
/// The top-left hand corner of the window relative to the top-left hand corner of the desktop.
|
||||||
|
///
|
||||||
|
/// Note that the top-left hand corner of the desktop is not necessarily the same as the
|
||||||
|
/// screen. If the user uses a desktop with multiple monitors, the top-left hand corner of
|
||||||
|
/// the desktop is the top-left hand corner of the monitor at the top-left of the desktop.
|
||||||
|
///
|
||||||
|
/// Platform-specific
|
||||||
|
/// * **iOS:** Can only be called on the main thread. Returns the top left coordinates of
|
||||||
|
/// the window in the screen space coordinate system.
|
||||||
|
/// * **Web:** Returns the top-left coordinates relative to the viewport.
|
||||||
|
/// * **Android / Wayland:** Always returns NotSupportedError.
|
||||||
|
pub outer_position: Option<Position>,
|
||||||
|
|
||||||
|
/// Returns the position of the top-left hand corner of the window’s client area relative to
|
||||||
|
/// the top-left hand corner of the desktop.
|
||||||
|
///
|
||||||
|
/// The same conditions that apply to `WindowOptions::outer_position` apply to this.
|
||||||
|
///
|
||||||
|
/// Platform-specific
|
||||||
|
/// * **iOS:** Can only be called on the main thread. Returns the top left coordinates of the
|
||||||
|
/// window’s safe area in the screen space coordinate system.
|
||||||
|
/// * **Web:** Returns the top-left coordinates relative to the viewport.
|
||||||
|
/// * **Android / Wayland:** Always returns NotSupportedError.
|
||||||
|
pub inner_position: Option<Position>,
|
||||||
|
|
||||||
/// Sets the window to maximized or back.
|
/// Sets the window to maximized or back.
|
||||||
///
|
///
|
||||||
/// Platform-specific:
|
/// Platform-specific:
|
||||||
|
@ -231,7 +280,7 @@ pub struct WindowOptions {
|
||||||
/// Platform-specific:
|
/// Platform-specific:
|
||||||
/// * Wayland / Windows: Not implemented.
|
/// * Wayland / Windows: Not implemented.
|
||||||
/// * iOS / Android / Web / Orbital: Unsupported.
|
/// * iOS / Android / Web / Orbital: Unsupported.
|
||||||
pub resize_increments: Option<Vec2>,
|
pub resize_increments: Option<Size>,
|
||||||
|
|
||||||
/// Sets the current window theme. Use None to fallback to system default.
|
/// Sets the current window theme. Use None to fallback to system default.
|
||||||
///
|
///
|
||||||
|
@ -277,7 +326,7 @@ impl Default for WindowOptions {
|
||||||
cursor_visible: true,
|
cursor_visible: true,
|
||||||
decorations: true,
|
decorations: true,
|
||||||
enabled_buttons: WindowButtons::all(),
|
enabled_buttons: WindowButtons::all(),
|
||||||
mode: WindowMode::Windowed,
|
fullscreen: None,
|
||||||
ime_allowed: false,
|
ime_allowed: false,
|
||||||
ime_cursor_area: Area::default(),
|
ime_cursor_area: Area::default(),
|
||||||
inner_size: Size::new_physical(800, 600),
|
inner_size: Size::new_physical(800, 600),
|
||||||
|
@ -294,10 +343,74 @@ impl Default for WindowOptions {
|
||||||
level: WindowLevel::Normal,
|
level: WindowLevel::Normal,
|
||||||
focused: false,
|
focused: false,
|
||||||
cursor_inside_window: false,
|
cursor_inside_window: false,
|
||||||
|
blur: false,
|
||||||
|
inner_position: None,
|
||||||
|
outer_position: None,
|
||||||
|
transparent: false,
|
||||||
|
visible: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WindowOptions {
|
||||||
|
pub(crate) fn as_winit_attributes(&self) -> winit::window::WindowAttributes {
|
||||||
|
let mut att = Window::default_attributes();
|
||||||
|
|
||||||
|
att.inner_size = Some(self.inner_size.into());
|
||||||
|
|
||||||
|
if let Some(min_inner_size) = self.min_inner_size {
|
||||||
|
att.min_inner_size = Some(min_inner_size.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(max_inner_size) = self.max_inner_size {
|
||||||
|
att.max_inner_size = Some(max_inner_size.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(position) = self.outer_position.clone()
|
||||||
|
.or(self.inner_position.clone())
|
||||||
|
{
|
||||||
|
att.position = Some(position.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
att.resizable = self.resizeable;
|
||||||
|
att.enabled_buttons = self.enabled_buttons.clone();
|
||||||
|
att.title = self.title.clone();
|
||||||
|
att.maximized = self.maximized;
|
||||||
|
att.visible = self.visible;
|
||||||
|
att.transparent = self.transparent;
|
||||||
|
att.blur = self.blur;
|
||||||
|
att.decorations = self.decorations;
|
||||||
|
//att.window_icon = self.icon.clone
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
|
||||||
|
/* winit::window::WindowAttributes {
|
||||||
|
inner_size: Some(self.inner_size.into()),
|
||||||
|
min_inner_size: self.min_inner_size.map(|v| v.into()),
|
||||||
|
max_inner_size: self.max_inner_size.map(|v| v.into()),
|
||||||
|
position: self.outer_position.clone().or(self.inner_position.clone()).map(|v| v.into()), // TODO: sync in system
|
||||||
|
resizable: self.resizeable,
|
||||||
|
enabled_buttons: self.enabled_buttons.clone(),
|
||||||
|
title: self.title.clone(),
|
||||||
|
maximized: self.maximized,
|
||||||
|
visible: self.visible, // TODO: sync in system
|
||||||
|
transparent: self.transparent, // TODO: sync in system
|
||||||
|
blur: self.blur, // TODO: sync in system
|
||||||
|
decorations: self.decorations,
|
||||||
|
window_icon: self.icon.clone(),
|
||||||
|
preferred_theme: self.theme,
|
||||||
|
resize_increments: self.resize_increments.map(|v| v.into()),
|
||||||
|
content_protected: self.content_protected,
|
||||||
|
window_level: self.level,
|
||||||
|
active: false, // TODO
|
||||||
|
cursor: self.cursor.clone(),
|
||||||
|
fullscreen: self.fullscreen.clone(),
|
||||||
|
parent_window: todo!(),
|
||||||
|
platform_specific: todo!(),
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct WindowPlugin {
|
pub struct WindowPlugin {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -373,17 +486,16 @@ fn center_mouse(window: &Window, options: &WindowOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
if let (Some(window), Some(opts)) = (
|
/* if let (Some(window), Some(opts)) = (
|
||||||
world.try_get_resource::<Arc<Window>>(),
|
world.try_get_resource::<Arc<Window>>(),
|
||||||
world.try_get_resource::<Ct<WindowOptions>>(),
|
world.try_get_resource::<Ct<WindowOptions>>(),
|
||||||
) {
|
) { */
|
||||||
// if the options changed, update the window
|
let tick = world.tick();
|
||||||
if opts.peek_changed() {
|
for (entity, mut opts, window_tick, windows) in world.view_iter::<(Entities, &mut WindowOptions, TickOf<WindowOptions>, ResMut<WinitWindows>)>() {
|
||||||
drop(opts); // drop the Ref, we're about to get a RefMut
|
let window = windows.get_entity_window(entity)
|
||||||
|
.expect("entity's window is missing");
|
||||||
// now we can get it mutable, this will trigger the ChangeTracker, so it will be reset at the end of this scope.
|
|
||||||
let mut opts = world.get_resource_mut::<Ct<WindowOptions>>();
|
|
||||||
|
|
||||||
|
if window_tick == tick {
|
||||||
if opts.focused {
|
if opts.focused {
|
||||||
window.focus_window();
|
window.focus_window();
|
||||||
}
|
}
|
||||||
|
@ -400,26 +512,7 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
window.set_cursor_visible(opts.cursor_visible); // TODO: Handle unsupported platforms
|
window.set_cursor_visible(opts.cursor_visible); // TODO: Handle unsupported platforms
|
||||||
window.set_decorations(opts.decorations); // TODO: Handle unsupported platforms
|
window.set_decorations(opts.decorations); // TODO: Handle unsupported platforms
|
||||||
window.set_enabled_buttons(opts.enabled_buttons); // TODO: Handle unsupported platforms
|
window.set_enabled_buttons(opts.enabled_buttons); // TODO: Handle unsupported platforms
|
||||||
|
window.set_fullscreen(opts.fullscreen.clone());
|
||||||
// Update the window mode. can only be done if the monitor is found
|
|
||||||
if let Some(monitor) = window
|
|
||||||
.current_monitor()
|
|
||||||
.or_else(|| window.primary_monitor())
|
|
||||||
.or_else(|| window.available_monitors().next())
|
|
||||||
{
|
|
||||||
match opts.mode {
|
|
||||||
WindowMode::Borderless => {
|
|
||||||
window.set_fullscreen(Some(Fullscreen::Borderless(Some(monitor))))
|
|
||||||
}
|
|
||||||
WindowMode::Fullscreen => window.set_fullscreen(Some(Fullscreen::Exclusive(
|
|
||||||
monitor.video_modes().next().unwrap(),
|
|
||||||
))),
|
|
||||||
WindowMode::Windowed => window.set_fullscreen(None),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warn!("Failure to get monitor handle, could not update WindowMode");
|
|
||||||
}
|
|
||||||
|
|
||||||
window.set_ime_allowed(opts.ime_allowed);
|
window.set_ime_allowed(opts.ime_allowed);
|
||||||
window.set_ime_cursor_area(opts.ime_cursor_area.position, opts.ime_cursor_area.size);
|
window.set_ime_cursor_area(opts.ime_cursor_area.position, opts.ime_cursor_area.size);
|
||||||
window.request_inner_size(opts.inner_size);
|
window.request_inner_size(opts.inner_size);
|
||||||
|
@ -432,20 +525,14 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
window.set_maximized(opts.maximized);
|
window.set_maximized(opts.maximized);
|
||||||
window.set_minimized(opts.minimized);
|
window.set_minimized(opts.minimized);
|
||||||
window.set_resizable(opts.resizeable);
|
window.set_resizable(opts.resizeable);
|
||||||
window.set_resize_increments(vec2_to_logical_size_op(opts.resize_increments));
|
window.set_resize_increments(opts.resize_increments);
|
||||||
window.set_theme(opts.theme);
|
window.set_theme(opts.theme);
|
||||||
window.set_title(&opts.title);
|
window.set_title(&opts.title);
|
||||||
window.set_window_icon(opts.icon.clone());
|
window.set_window_icon(opts.icon.clone());
|
||||||
window.set_window_level(opts.level);
|
window.set_window_level(opts.level);
|
||||||
|
|
||||||
// reset the tracker after we mutably used it
|
|
||||||
opts.reset();
|
|
||||||
|
|
||||||
center_mouse(&window, &opts);
|
center_mouse(&window, &opts);
|
||||||
} else {
|
} else {
|
||||||
drop(opts); // drop the Ref, we're about to get a RefMut
|
|
||||||
let mut opts = world.get_resource_mut::<Ct<WindowOptions>>();
|
|
||||||
|
|
||||||
if let Some(event_queue) = world.try_get_resource_mut::<EventQueue>() {
|
if let Some(event_queue) = world.try_get_resource_mut::<EventQueue>() {
|
||||||
if let Some(events) = event_queue.read_events::<InputEvent>() {
|
if let Some(events) = event_queue.read_events::<InputEvent>() {
|
||||||
for ev in events {
|
for ev in events {
|
||||||
|
@ -463,11 +550,7 @@ fn window_updater_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the stored state of the window to match the actual window
|
// update the stored state of the window to match the actual window
|
||||||
|
|
||||||
opts.focused = window.has_focus();
|
opts.focused = window.has_focus();
|
||||||
|
|
||||||
opts.reset();
|
|
||||||
|
|
||||||
center_mouse(&window, &opts);
|
center_mouse(&window, &opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use lyra_ecs::Entity;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use tracing::debug;
|
||||||
|
use winit::{application::ApplicationHandler, event_loop::{ActiveEventLoop, EventLoop}, window::{Window, WindowAttributes, WindowId}};
|
||||||
|
|
||||||
|
use crate::{game::App, plugin::Plugin, render::window::WindowOptions};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WinitPlugin;
|
||||||
|
|
||||||
|
impl Plugin for WinitPlugin {
|
||||||
|
fn setup(&self, app: &mut crate::game::App) {
|
||||||
|
app.set_run_fn(winit_app_runner);
|
||||||
|
app.add_resource(WinitWindows::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self, app: &mut crate::game::App) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(&self, app: &mut crate::game::App) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cleanup(&self, app: &mut crate::game::App) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct WinitWindows {
|
||||||
|
pub windows: FxHashMap<WindowId, Arc<Window>>,
|
||||||
|
pub entity_to_window: FxHashMap<Entity, WindowId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WinitWindows {
|
||||||
|
pub fn create_window(&mut self, event_loop: &ActiveEventLoop, entity: Entity, attr: WindowAttributes) -> Result<WindowId, winit::error::OsError> {
|
||||||
|
let win = event_loop.create_window(attr)?;
|
||||||
|
let id = win.id();
|
||||||
|
|
||||||
|
self.windows.insert(id, Arc::new(win));
|
||||||
|
self.entity_to_window.insert(entity, id);
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entity_window(&self, entity: Entity) -> Option<&Arc<Window>> {
|
||||||
|
self.entity_to_window.get(&entity)
|
||||||
|
.and_then(|id| self.windows.get(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn winit_app_runner(mut app: App) {
|
||||||
|
let evloop = EventLoop::new()
|
||||||
|
.expect("failed to create winit EventLoop");
|
||||||
|
|
||||||
|
evloop.run_app(&mut app)
|
||||||
|
.expect("loop error");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* struct WinitRunner {
|
||||||
|
app: App
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for WinitRunner {
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
debug!("resumed")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &ActiveEventLoop,
|
||||||
|
window_id: WindowId,
|
||||||
|
event: winit::event::WindowEvent,
|
||||||
|
) {
|
||||||
|
let world = &mut self.app.world;
|
||||||
|
let mut windows = world.get_resource_mut::<WinitWindows>();
|
||||||
|
|
||||||
|
let window = match windows.windows.get_mut(&window_id) {
|
||||||
|
Some(w) => w,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} */
|
Loading…
Reference in New Issue