Create window, handle simple input
This commit is contained in:
commit
a086e5b24a
|
@ -0,0 +1 @@
|
|||
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
|||
[package]
|
||||
name = "lyra-engine"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
shipyard = "0.6.2"
|
||||
winit = "0.28.1"
|
||||
#winit-modular = "0.1.1"
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.16", features = [ "tracing-log" ] }
|
||||
tracing-log = "0.1.3"
|
||||
wgpu = "0.15.1"
|
||||
async-std = { version = "1.12.0", features = [ "unstable", "attributes" ] }
|
||||
cfg-if = "1"
|
||||
bytemuck = { version = "1.12", features = [ "derive" ] }
|
||||
image = { version = "0.24", default-features = false, features = ["png", "jpeg"] }
|
||||
anyhow = "1.0"
|
||||
cgmath = "0.18"
|
||||
tobj = { version = "3.2.1", features = [
|
||||
"async",
|
||||
]}
|
||||
instant = "0.1"
|
||||
async-trait = "0.1.65"
|
|
@ -0,0 +1,18 @@
|
|||
{ pkgs ? import <nixpkgs> { } }:
|
||||
|
||||
with pkgs;
|
||||
|
||||
mkShell rec {
|
||||
nativeBuildInputs = [
|
||||
pkg-config
|
||||
openssl
|
||||
wasm-pack
|
||||
trunk
|
||||
];
|
||||
buildInputs = [
|
||||
udev alsa-lib vulkan-loader
|
||||
xorg.libX11 xorg.libXcursor xorg.libXi xorg.libXrandr # To use the x11 feature
|
||||
libxkbcommon wayland # To use the wayland feature
|
||||
];
|
||||
LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
use std::any::Any;
|
||||
|
||||
pub trait Component {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Entity {
|
||||
pub handle: i32,
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
pub fn new(handle: i32) -> Self {
|
||||
Self {
|
||||
handle
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub mod entity;
|
||||
pub mod registry;
|
||||
pub mod component;
|
|
@ -0,0 +1,131 @@
|
|||
use std::{collections::HashMap, cell::{RefCell, RefMut, Ref}, rc::Rc, borrow::BorrowMut, any::Any, ops::Deref};
|
||||
|
||||
use super::{entity::Entity, component::Component};
|
||||
|
||||
pub trait Registry {
|
||||
/// Create an entity
|
||||
fn create_entity(&mut self) -> Entity;
|
||||
|
||||
/// Remove the entity from the registry. Its components will also be destroyed
|
||||
fn destroy_entity(&mut self, entity: Entity);
|
||||
|
||||
/// Add a component to an entity
|
||||
fn entity_add_component<C: Component + 'static>(&mut self, entity: Entity, component: C) -> Option<Rc<RefCell<C>>>; // TODO: Return result if the component is already added.
|
||||
|
||||
/// Remove a component from an entity
|
||||
fn entity_remove_component<C: Component + 'static>(&mut self, entity: Entity) -> bool;
|
||||
|
||||
fn entity_has_component<C: Component + 'static>(&self, entity: Entity) -> bool;
|
||||
|
||||
/// Get all the components that an entity has
|
||||
fn entity_get_components(&self, entity: Entity) -> Option<Vec<Rc<RefCell<dyn Component>>>>;
|
||||
|
||||
/// Get a component of a specific type.
|
||||
fn entity_get_component<C: Component + 'static>(&self, entity: Entity) -> Option<RefMut<'_, C>>;
|
||||
}
|
||||
|
||||
pub struct BasicRegistry {
|
||||
next_handle: i32,
|
||||
map: HashMap<Entity, Vec<Rc<RefCell<dyn Component>>>>,
|
||||
}
|
||||
|
||||
impl BasicRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
next_handle: 0,
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Registry for BasicRegistry {
|
||||
fn create_entity(&mut self) -> Entity {
|
||||
//self.map.insert()
|
||||
let entity = Entity::new(self.next_handle);
|
||||
self.next_handle += 1;
|
||||
|
||||
self.map.insert(entity, Vec::new());
|
||||
|
||||
entity
|
||||
}
|
||||
|
||||
fn destroy_entity(&mut self, entity: Entity) {
|
||||
self.map.remove(&entity);
|
||||
}
|
||||
|
||||
fn entity_add_component<C: Component + 'static>(&mut self, entity: Entity, component: C) -> Option<Rc<RefCell<C>>> {
|
||||
if let Some(components) = self.map.get_mut(&entity) {
|
||||
let rc = Rc::new(RefCell::new(component));
|
||||
let clone = Rc::clone(&rc);
|
||||
|
||||
components.push(rc);
|
||||
|
||||
return Some(clone);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn entity_remove_component<C: Component + 'static>(&mut self, entity: Entity) -> bool {
|
||||
if let Some(components) = self.map.get_mut(&entity) {
|
||||
let mut removed = false;
|
||||
components.retain(|component| {
|
||||
if removed {
|
||||
return true;
|
||||
}
|
||||
|
||||
let borrowed_comp = component.deref().borrow_mut();
|
||||
let any_comp = borrowed_comp.as_any();
|
||||
|
||||
if any_comp.is::<C>() {
|
||||
removed = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
return removed;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn entity_has_component<C: Component + 'static>(&self, entity: Entity) -> bool {
|
||||
if let Some(components) = self.map.get(&entity) {
|
||||
for component in components.iter() {
|
||||
let borrowed_comp = component.deref().borrow_mut();
|
||||
let any_comp = borrowed_comp.as_any();
|
||||
if any_comp.is::<C>() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn entity_get_components(&self, entity: Entity) -> Option<Vec<Rc<RefCell<dyn Component>>>> {
|
||||
if let Some(components) = self.map.get(&entity) {
|
||||
let mut cloned_components = Vec::new();
|
||||
|
||||
for component in components.iter() {
|
||||
cloned_components.push(Rc::clone(&component));
|
||||
}
|
||||
|
||||
return Some(cloned_components);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn entity_get_component<C: Component + 'static>(&self, entity: Entity) -> Option<RefMut<'_, C>> {
|
||||
if let Some(components) = self.map.get(&entity) {
|
||||
for component in components.iter() {
|
||||
let borrowed_comp = component.deref().borrow_mut();
|
||||
let any_comp = borrowed_comp.as_any();
|
||||
if any_comp.is::<C>() {
|
||||
return Some(RefMut::map(borrowed_comp, |c| c.as_any_mut().downcast_mut().unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
use std::{sync::Arc, ops::Deref};
|
||||
|
||||
use async_std::{task::block_on, sync::Mutex};
|
||||
use shipyard::{World, Workload};
|
||||
use tracing::{metadata::LevelFilter, info, debug, Level, warn};
|
||||
/* use tracing_subscriber::{filter::FilterFn, util::SubscriberInitExt};
|
||||
use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; */
|
||||
use tracing_subscriber::{
|
||||
layer::{Layer, SubscriberExt},
|
||||
filter::FilterFn,
|
||||
util::SubscriberInitExt,
|
||||
};
|
||||
|
||||
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode}, event_loop::{EventLoop, ControlFlow}};
|
||||
|
||||
use crate::{renderer::{Renderer, BasicRenderer}, input_event::InputEvent};
|
||||
|
||||
struct GameLoop {
|
||||
window: Arc<Window>,
|
||||
renderer: Box<dyn Renderer>,
|
||||
}
|
||||
|
||||
impl GameLoop {
|
||||
pub async fn new(window: &Arc<Window>) -> Self {
|
||||
Self {
|
||||
window: Arc::clone(&window),
|
||||
renderer: Box::new(BasicRenderer::create_with_window(Arc::clone(window)).await),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
||||
self.renderer.on_resize(new_size).await;
|
||||
}
|
||||
|
||||
pub fn run_sync(&mut self, event: Event<()>, control_flow: &mut ControlFlow) {
|
||||
block_on(self.run_event_loop(event, control_flow))
|
||||
}
|
||||
|
||||
async fn update(&mut self) {
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn input_update(&mut self, event: &InputEvent) -> Option<ControlFlow> {
|
||||
match event {
|
||||
InputEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
state: ElementState::Pressed,
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
self.on_exit();
|
||||
|
||||
Some(ControlFlow::Exit)
|
||||
},
|
||||
|
||||
_ => {
|
||||
debug!("Got unhandled input event: \"{:?}\"", event);
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_window() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render_item() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn on_exit(&mut self) {
|
||||
info!("On exit!");
|
||||
}
|
||||
|
||||
pub async fn run_event_loop(&mut self, event: Event<'_, ()>, control_flow: &mut ControlFlow) {
|
||||
*control_flow = ControlFlow::Poll;
|
||||
match event {
|
||||
Event::WindowEvent {
|
||||
ref event,
|
||||
window_id,
|
||||
} if window_id == self.window.id() => {
|
||||
// If try_from failed, that means that the WindowEvent is not an
|
||||
// input related event.
|
||||
if let Ok(input_event) = InputEvent::try_from(event) {
|
||||
if let Some(new_control) = self.input_update(&input_event).await {
|
||||
*control_flow = new_control;
|
||||
}
|
||||
} else {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
self.on_exit();
|
||||
|
||||
*control_flow = ControlFlow::Exit
|
||||
},
|
||||
|
||||
WindowEvent::Resized(physical_size) => {
|
||||
self.on_resize(*physical_size).await;
|
||||
},
|
||||
|
||||
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
||||
self.on_resize(**new_inner_size).await;
|
||||
},
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Event::RedrawRequested(window_id) if window_id == self.window.id() => {
|
||||
match self.renderer.as_mut().render().await {
|
||||
Ok(_) => {}
|
||||
// Reconfigure the surface if lost
|
||||
Err(wgpu::SurfaceError::Lost) => self.on_resize(self.renderer.as_ref().size()).await,
|
||||
// The system is out of memory, we should probably quit
|
||||
Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
|
||||
// All other errors (Outdated, Timeout) should be resolved by the next frame
|
||||
Err(e) => eprintln!("{:?}", e),
|
||||
}
|
||||
},
|
||||
|
||||
Event::MainEventsCleared => {
|
||||
self.window.request_redraw();
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Game {
|
||||
|
||||
}
|
||||
|
||||
impl Game {
|
||||
/* fn lyra_engine_log_filter() {
|
||||
|
||||
} */
|
||||
|
||||
pub async fn initialize() -> Self {
|
||||
let filter = FilterFn::new(|metadata| {
|
||||
//metadata.
|
||||
//println!("Metadata: {:?}", metadata);
|
||||
|
||||
metadata.module_path()
|
||||
.unwrap_or_else(|| metadata.target())
|
||||
.starts_with("lyra_engine") && (LevelFilter::INFO >= metadata.level().to_owned())
|
||||
});
|
||||
|
||||
let layer = tracing_subscriber::fmt::layer();
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(layer.with_filter(filter))
|
||||
.init();
|
||||
|
||||
Self {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn update() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn input_update() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render_window() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn render_item() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn exit() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn run(&mut self) {
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
|
||||
let mut g_loop = GameLoop::new(&Arc::new(window)).await;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
g_loop.run_sync(event, control_flow);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
use winit::{event::{DeviceId, KeyboardInput, ModifiersState, MouseScrollDelta, TouchPhase, MouseButton, AxisId, Touch, WindowEvent, ElementState}, dpi::PhysicalPosition};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum InputEvent {
|
||||
/// An event from the keyboard has been received.
|
||||
KeyboardInput {
|
||||
device_id: DeviceId,
|
||||
input: KeyboardInput,
|
||||
|
||||
/// If true, the event was generated synthetically by winit in one of the following circumstances:
|
||||
/// Synthetic key press events are generated for all keys pressed when a window gains focus.
|
||||
/// Likewise, synthetic key release events are generated for all keys pressed when a window goes out of focus.
|
||||
/// Currently, this is only functional on X11 and Windows
|
||||
is_synthetic: bool,
|
||||
},
|
||||
|
||||
/// The cursor has moved on the window.
|
||||
CursorMoved {
|
||||
device_id: DeviceId,
|
||||
position: PhysicalPosition<f64>,
|
||||
modifiers: ModifiersState,
|
||||
},
|
||||
|
||||
/// The cursor has entered the window.
|
||||
CursorEntered {
|
||||
device_id: DeviceId,
|
||||
},
|
||||
|
||||
/// The cursor has left the window.
|
||||
CursorLeft {
|
||||
device_id: DeviceId,
|
||||
},
|
||||
|
||||
/// A mouse wheel movement or touchpad scroll occurred.
|
||||
MouseWheel {
|
||||
device_id: DeviceId,
|
||||
delta: MouseScrollDelta,
|
||||
phase: TouchPhase,
|
||||
/// Deprecated in favor of WindowEvent::ModifiersChanged
|
||||
modifiers: ModifiersState,
|
||||
},
|
||||
|
||||
/// An mouse button press has been received.
|
||||
MouseInput {
|
||||
device_id: DeviceId,
|
||||
state: ElementState,
|
||||
button: MouseButton,
|
||||
#[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
|
||||
modifiers: ModifiersState,
|
||||
},
|
||||
|
||||
/// Touchpad magnification event with two-finger pinch gesture.
|
||||
/// Positive delta values indicate magnification (zooming in) and negative delta values indicate shrinking (zooming out).
|
||||
///
|
||||
/// Note: Only available on macOS
|
||||
TouchpadMagnify {
|
||||
device_id: DeviceId,
|
||||
delta: f64,
|
||||
phase: TouchPhase,
|
||||
},
|
||||
|
||||
/// Smart magnification event.
|
||||
///
|
||||
/// On a Mac, smart magnification is triggered by a double tap with two fingers
|
||||
/// on the trackpad and is commonly used to zoom on a certain object
|
||||
/// (e.g. a paragraph of a PDF) or (sort of like a toggle) to reset any zoom.
|
||||
/// The gesture is also supported in Safari, Pages, etc.
|
||||
///
|
||||
/// The event is general enough that its generating gesture is allowed to vary
|
||||
/// across platforms. It could also be generated by another device.
|
||||
///
|
||||
/// Unfortunatly, neither [Windows](https://support.microsoft.com/en-us/windows/touch-gestures-for-windows-a9d28305-4818-a5df-4e2b-e5590f850741)
|
||||
/// nor [Wayland](https://wayland.freedesktop.org/libinput/doc/latest/gestures.html)
|
||||
/// support this gesture or any other gesture with the same effect.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **macOS 10.8** and later.
|
||||
SmartMagnify { device_id: DeviceId },
|
||||
|
||||
/// Touchpad rotation event with two-finger rotation gesture.
|
||||
///
|
||||
/// Positive delta values indicate rotation counterclockwise and
|
||||
/// negative delta values indicate rotation clockwise.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - Only available on **macOS**.
|
||||
TouchpadRotate {
|
||||
device_id: DeviceId,
|
||||
delta: f32,
|
||||
phase: TouchPhase,
|
||||
},
|
||||
|
||||
/// Touchpad pressure event.
|
||||
///
|
||||
/// At the moment, only supported on Apple forcetouch-capable macbooks.
|
||||
/// The parameters are: pressure level (value between 0 and 1 representing how hard the touchpad
|
||||
/// is being pressed) and stage (integer representing the click level).
|
||||
TouchpadPressure {
|
||||
device_id: DeviceId,
|
||||
pressure: f32,
|
||||
stage: i64,
|
||||
},
|
||||
|
||||
/// Motion on some analog axis. May report data redundant to other, more specific events.
|
||||
AxisMotion {
|
||||
device_id: DeviceId,
|
||||
axis: AxisId,
|
||||
value: f64,
|
||||
},
|
||||
|
||||
/// Touch event has been received
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **macOS:** Unsupported.
|
||||
Touch(Touch),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum InputEventConversionError<'a> {
|
||||
FromError(&'a WindowEvent<'a>)
|
||||
}
|
||||
|
||||
impl<'a> Into<WindowEvent<'a>> for InputEvent {
|
||||
fn into(self) -> WindowEvent<'a> {
|
||||
match self {
|
||||
InputEvent::KeyboardInput { device_id, input, is_synthetic } => WindowEvent::KeyboardInput { device_id, input, is_synthetic },
|
||||
InputEvent::CursorMoved { device_id, position, modifiers } => WindowEvent::CursorMoved { device_id, position, modifiers },
|
||||
InputEvent::CursorEntered { device_id } => WindowEvent::CursorEntered { device_id },
|
||||
InputEvent::CursorLeft { device_id } => WindowEvent::CursorLeft { device_id },
|
||||
InputEvent::MouseWheel { device_id, delta, phase, modifiers } => WindowEvent::MouseWheel { device_id, delta, phase, modifiers },
|
||||
InputEvent::MouseInput { device_id, state, button, modifiers } => WindowEvent::MouseInput { device_id, state, button, modifiers },
|
||||
InputEvent::TouchpadMagnify { device_id, delta, phase } => WindowEvent::TouchpadMagnify { device_id, delta, phase },
|
||||
InputEvent::SmartMagnify { device_id } => WindowEvent::SmartMagnify { device_id },
|
||||
InputEvent::TouchpadRotate { device_id, delta, phase } => WindowEvent::TouchpadRotate { device_id, delta, phase },
|
||||
InputEvent::TouchpadPressure { device_id, pressure, stage } => WindowEvent::TouchpadPressure { device_id, pressure, stage },
|
||||
InputEvent::AxisMotion { device_id, axis, value } => WindowEvent::AxisMotion { device_id, axis, value },
|
||||
InputEvent::Touch(t) => WindowEvent::Touch(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a WindowEvent<'a>> for InputEvent {
|
||||
type Error = InputEventConversionError<'a>;
|
||||
|
||||
fn try_from(value: &'a WindowEvent<'a>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
WindowEvent::KeyboardInput { device_id, input, is_synthetic } =>
|
||||
Ok(InputEvent::KeyboardInput {
|
||||
device_id: device_id.clone(),
|
||||
input: input.clone(),
|
||||
is_synthetic: is_synthetic.clone()
|
||||
}),
|
||||
WindowEvent::CursorMoved { device_id, position, modifiers } =>
|
||||
Ok(InputEvent::CursorMoved {
|
||||
device_id: device_id.clone(),
|
||||
position: position.clone(),
|
||||
modifiers: modifiers.clone()
|
||||
}),
|
||||
WindowEvent::CursorEntered { device_id } =>
|
||||
Ok(InputEvent::CursorEntered {
|
||||
device_id: device_id.clone()
|
||||
}),
|
||||
WindowEvent::CursorLeft { device_id } =>
|
||||
Ok(InputEvent::CursorLeft {
|
||||
device_id: device_id.clone()
|
||||
}),
|
||||
WindowEvent::MouseWheel { device_id, delta, phase, modifiers } =>
|
||||
Ok(InputEvent::MouseWheel {
|
||||
device_id: device_id.clone(),
|
||||
delta: delta.clone(),
|
||||
phase: phase.clone(),
|
||||
modifiers: modifiers.clone()
|
||||
}),
|
||||
WindowEvent::MouseInput { device_id, state, button, modifiers } =>
|
||||
Ok(InputEvent::MouseInput {
|
||||
device_id: device_id.clone(),
|
||||
state: state.clone(),
|
||||
button: button.clone(),
|
||||
modifiers: modifiers.clone()
|
||||
}),
|
||||
WindowEvent::TouchpadMagnify { device_id, delta, phase } =>
|
||||
Ok(InputEvent::TouchpadMagnify {
|
||||
device_id: device_id.clone(),
|
||||
delta: delta.clone(),
|
||||
phase: phase.clone()
|
||||
}),
|
||||
WindowEvent::SmartMagnify { device_id } =>
|
||||
Ok(InputEvent::SmartMagnify {
|
||||
device_id: device_id.clone()
|
||||
}),
|
||||
WindowEvent::TouchpadRotate { device_id, delta, phase } =>
|
||||
Ok(InputEvent::TouchpadRotate {
|
||||
device_id: device_id.clone(),
|
||||
delta: delta.clone(),
|
||||
phase: phase.clone()
|
||||
}),
|
||||
WindowEvent::TouchpadPressure { device_id, pressure, stage } =>
|
||||
Ok(InputEvent::TouchpadPressure {
|
||||
device_id: device_id.clone(),
|
||||
pressure: pressure.clone(),
|
||||
stage: stage.clone()
|
||||
}),
|
||||
WindowEvent::AxisMotion { device_id, axis, value } =>
|
||||
Ok(InputEvent::AxisMotion {
|
||||
device_id: device_id.clone(),
|
||||
axis: axis.clone(),
|
||||
value: value.clone()
|
||||
}),
|
||||
WindowEvent::Touch(t) => Ok(InputEvent::Touch(t.clone())),
|
||||
|
||||
_ => Err(InputEventConversionError::FromError(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* impl<'a> TryFrom<WindowEvent<'a>> for InputEvent {
|
||||
type Error = InputEventConversionError<'a>;
|
||||
|
||||
fn try_from(value: WindowEvent<'a>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
WindowEvent::KeyboardInput { device_id, input, is_synthetic } =>
|
||||
Ok(InputEvent::KeyboardInput { device_id, input, is_synthetic }),
|
||||
WindowEvent::CursorMoved { device_id, position, modifiers } =>
|
||||
Ok(InputEvent::CursorMoved { device_id, position, modifiers }),
|
||||
WindowEvent::CursorEntered { device_id } => Ok(InputEvent::CursorEntered { device_id }),
|
||||
WindowEvent::CursorLeft { device_id } => Ok(InputEvent::CursorLeft { device_id }),
|
||||
WindowEvent::MouseWheel { device_id, delta, phase, modifiers } =>
|
||||
Ok(InputEvent::MouseWheel { device_id, delta, phase, modifiers }),
|
||||
WindowEvent::MouseInput { device_id, state, button, modifiers } =>
|
||||
Ok(InputEvent::MouseInput { device_id, state, button, modifiers }),
|
||||
WindowEvent::TouchpadMagnify { device_id, delta, phase } =>
|
||||
Ok(InputEvent::TouchpadMagnify { device_id, delta, phase }),
|
||||
WindowEvent::SmartMagnify { device_id } => Ok(InputEvent::SmartMagnify { device_id }),
|
||||
WindowEvent::TouchpadRotate { device_id, delta, phase } =>
|
||||
Ok(InputEvent::TouchpadRotate { device_id, delta, phase }),
|
||||
WindowEvent::TouchpadPressure { device_id, pressure, stage } =>
|
||||
Ok(InputEvent::TouchpadPressure { device_id, pressure, stage }),
|
||||
WindowEvent::AxisMotion { device_id, axis, value } =>
|
||||
Ok(InputEvent::AxisMotion { device_id, axis, value }),
|
||||
WindowEvent::Touch(t) => Ok(InputEvent::Touch(t)),
|
||||
|
||||
_ => Err(InputEventConversionError::FromError(value))
|
||||
}
|
||||
}
|
||||
} */
|
|
@ -0,0 +1,62 @@
|
|||
mod system;
|
||||
mod game;
|
||||
mod renderer;
|
||||
//mod ecs;
|
||||
mod input_event;
|
||||
|
||||
use game::Game;
|
||||
|
||||
use shipyard::{Component, World, EntitiesViewMut, ViewMut, Get, Workload};
|
||||
use shipyard::IntoWorkload;
|
||||
|
||||
//use ecs::{registry::Registry, component::Component};
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
struct Point2d {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
impl Point2d {
|
||||
pub fn new(x: i32, y: i32) -> Self {
|
||||
Self {
|
||||
x,
|
||||
y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let mut world = World::new();
|
||||
|
||||
let entity = world.add_entity(Point2d::new(10, 10));
|
||||
let entity2 = world.add_entity(Point2d::new(846, 2188));
|
||||
|
||||
world.run(
|
||||
|mut vm_point: ViewMut<Point2d>| {
|
||||
let mut p = (&mut vm_point).get(entity).unwrap();
|
||||
|
||||
println!("Point: {:?}", p);
|
||||
p.x = 100;
|
||||
println!("Point after: {:?}", p);
|
||||
drop(p);
|
||||
|
||||
let mut p = (&mut vm_point).get(entity2).unwrap();
|
||||
|
||||
println!("Point: {:?}", p);
|
||||
p.x = 1000;
|
||||
println!("Point after: {:?}", p);
|
||||
|
||||
//let mut vm_
|
||||
//println!("Point2d: {:?}", vm_point.get);
|
||||
/* let empty_entity = entities.add_entity((), ());
|
||||
let single_component = entities.add_entity(&mut vm_pos, Pos::new());
|
||||
let multiple_components =
|
||||
entities.add_entity((&mut vm_pos, &mut vm_vel), (Pos::new(), Vel::new())); */
|
||||
},
|
||||
);
|
||||
|
||||
let mut game = Game::initialize().await;
|
||||
game.run().await;
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
//use winit::{window::Window, event::WindowEvent};
|
||||
//use winit::window::Window;
|
||||
use winit::{window::Window, event::WindowEvent};
|
||||
|
||||
#[async_trait]
|
||||
pub trait Renderer {
|
||||
//fn new(surface: wgpu::Surface, config: wgpu::SurfaceConfiguration, device: wgpu::Device)
|
||||
//async fn create_with_window(window: Window) -> Self;
|
||||
async fn render(&mut self) -> Result<(), wgpu::SurfaceError>;
|
||||
async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>);
|
||||
|
||||
fn size(&self) -> winit::dpi::PhysicalSize<u32>;
|
||||
}
|
||||
|
||||
pub struct BasicRenderer {
|
||||
pub surface: wgpu::Surface,
|
||||
pub device: wgpu::Device,
|
||||
pub queue: wgpu::Queue,
|
||||
pub config: wgpu::SurfaceConfiguration,
|
||||
pub size: winit::dpi::PhysicalSize<u32>,
|
||||
pub window: Arc<Window>,
|
||||
|
||||
pub clear_color: wgpu::Color,
|
||||
|
||||
pub render_pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl BasicRenderer {
|
||||
pub async fn create_with_window(window: Arc<Window>) -> BasicRenderer {
|
||||
let size = window.inner_size();
|
||||
|
||||
// Get a GPU handle
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::all(),
|
||||
dx12_shader_compiler: Default::default(),
|
||||
});
|
||||
|
||||
// This should be safe since surface will live as long as the window that created it
|
||||
let surface = unsafe { instance.create_surface(window.as_ref()) }.unwrap();
|
||||
|
||||
let adapter = instance.request_adapter(
|
||||
&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::default(),
|
||||
compatible_surface: Some(&surface),
|
||||
force_fallback_adapter: false,
|
||||
},
|
||||
).await.unwrap();
|
||||
|
||||
let (device, queue) = adapter.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
features: wgpu::Features::empty(),
|
||||
// WebGL does not support all wgpu features.
|
||||
// Not sure if the engine will ever completely support WASM,
|
||||
// but its here just in case
|
||||
limits: if cfg!(target_arch = "wasm32") {
|
||||
wgpu::Limits::downlevel_webgl2_defaults()
|
||||
} else {
|
||||
wgpu::Limits::default()
|
||||
},
|
||||
label: None,
|
||||
},
|
||||
None,
|
||||
).await.unwrap();
|
||||
|
||||
let surface_caps = surface.get_capabilities(&adapter);
|
||||
|
||||
let surface_format = surface_caps.formats.iter()
|
||||
.copied()
|
||||
.filter(|f| f.describe().srgb)
|
||||
.next()
|
||||
.unwrap_or(surface_caps.formats[0]);
|
||||
let config = wgpu::SurfaceConfiguration {
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
format: surface_format,
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
present_mode: surface_caps.present_modes[0],
|
||||
alpha_mode: surface_caps.alpha_modes[0],
|
||||
view_formats: vec![],
|
||||
};
|
||||
surface.configure(&device, &config);
|
||||
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("Shader"),
|
||||
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
|
||||
});
|
||||
|
||||
// Create a render pipeline. At some point this will be created by something else and given to the renderer
|
||||
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Render Pipeline Layout"),
|
||||
bind_group_layouts: &[],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Render Pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: "fs_main",
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: config.format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: Some(wgpu::Face::Back),
|
||||
// Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
// Requires Features::DEPTH_CLIP_CONTROL
|
||||
unclipped_depth: false,
|
||||
// Requires Features::CONSERVATIVE_RASTERIZATION
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
});
|
||||
|
||||
Self {
|
||||
window,
|
||||
surface,
|
||||
device,
|
||||
queue,
|
||||
config,
|
||||
size,
|
||||
clear_color: wgpu::Color {
|
||||
r: 0.1,
|
||||
g: 0.2,
|
||||
b: 0.3,
|
||||
a: 1.0,
|
||||
},
|
||||
render_pipeline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Renderer for BasicRenderer {
|
||||
|
||||
async fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||
let output = self.surface.get_current_texture()?;
|
||||
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("Basic Renderer's Encoder")
|
||||
});
|
||||
|
||||
{
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Basic Renderer's Render Pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(self.clear_color),
|
||||
store: true,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(&self.render_pipeline);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
self.queue.submit(std::iter::once(encoder.finish()));
|
||||
output.present();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
||||
if new_size.width > 0 && new_size.height > 0 {
|
||||
self.size = new_size;
|
||||
self.config.width = new_size.width;
|
||||
self.config.height = new_size.height;
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
}
|
||||
}
|
||||
|
||||
fn size(&self) -> winit::dpi::PhysicalSize<u32> {
|
||||
self.size
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// Vertex shader
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
@builtin(vertex_index) in_vertex_index: u32,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
let x = f32(1 - i32(in_vertex_index)) * 0.5;
|
||||
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
|
||||
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fragment shader
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(0.3, 0.2, 0.1, 1.0);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
use std::time::Duration;
|
||||
|
||||
trait System {
|
||||
fn new();
|
||||
|
||||
fn update(dt: Duration);
|
||||
fn input_update(dt: Duration);
|
||||
fn render(interopolate_alpha: f32, dt: Duration);
|
||||
fn destroy();
|
||||
}
|
Loading…
Reference in New Issue