diff --git a/Cargo.toml b/Cargo.toml index f6d25fc..e9e66a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,8 @@ crossbeam = "0.8.0" toml = "0.5.8" cgmath = "0.18.0" -rapier3d = { version = "0.5.0", features = ["simd-nightly", "parallel"] } -nalgebra = "0.24.1" +rapier3d = { version = "0.11.1", features = ["simd-nightly", "parallel"] } +nalgebra = "0.29.0" legion = "0.3.1" wgpu = "0.7.0" imgui = "0.7.0" diff --git a/exportToHTML/camera.rs.html b/exportToHTML/camera.rs.html new file mode 100644 index 0000000..29827fe --- /dev/null +++ b/exportToHTML/camera.rs.html @@ -0,0 +1,213 @@ + +
+1 use std::f32::consts::{FRAC_PI_2, PI}; +2 use std::time::{Duration, Instant}; +3 +4 use cgmath::{Decomposed, InnerSpace, Matrix4, Point3, Rad, Vector3}; +5 use winit_24::dpi::{LogicalPosition, PhysicalPosition}; +6 use winit_24::event::{ElementState, MouseScrollDelta, VirtualKeyCode}; +7 use crate::render::OPENGL_TO_WGPU_MATRIX; +8 use imgui::Condition; +9 use imgui::*; +10 +11 #[derive(Clone, Copy, Debug, PartialEq)] +12 pub struct Camera { +13 pub position: Point3<f32>, +14 pub yaw: Rad<f32>, +15 pub pitch: Rad<f32>, +16 } +17 +18 impl Camera { +19 pub fn new<V: Into<Point3<f32>>, Y: Into<Rad<f32>>, P: Into<Rad<f32>>>( +20 position: V, +21 yaw: Y, +22 pitch: P, +23 ) -> Self { +24 Self { +25 position: position.into(), +26 yaw: yaw.into(), +27 pitch: pitch.into(), +28 } +29 } +30 +31 pub fn calc_matrix(&self, projection: cgmath::Matrix4<f32>) -> Matrix4<f32> { +32 +33 let view_vector = Point3::new( +34 (1.0 * self.pitch.0.sin() * self.yaw.0.sin()), +35 (1.0 * self.pitch.0.cos()), +36 (1.0 * self.pitch.0.sin() * self.yaw.0.cos()), +37 ); +38 +39 let mx_view = Matrix4::look_at( +40 self.position, +41 Point3::new( +42 view_vector.x + self.position.x, +43 view_vector.y + self.position.y, +44 view_vector.z + self.position.z, +45 ), +46 Vector3::unit_y(), +47 ); +48 // I don't know how this works, but it limits pitching to like +49 // 70 degrees. Lame +50 // let mx_view = Matrix4::look_at_dir( +51 // self.position, +52 // Vector3::new( +53 // self.yaw.0.cos(), +54 // self.pitch.0.sin(), +55 // self.yaw.0.sin(), +56 // ).normalize(), +57 // Vector3::unit_y(), +58 // ); +59 let mx_correction = OPENGL_TO_WGPU_MATRIX; +60 mx_correction * projection * mx_view +61 } +62 } +63 +64 #[derive(Debug)] +65 pub struct CameraController { +66 amount_left: f32, +67 amount_right: f32, +68 amount_forward: f32, +69 amount_backward: f32, +70 amount_up: f32, +71 amount_down: f32, +72 rotate_horizontal: f32, +73 rotate_vertical: f32, +74 scroll: f32, +75 speed: f32, +76 sensitivity: f32, +77 active: bool, +78 } +79 +80 impl CameraController { +81 pub fn new(speed: f32, sensitivity: f32) -> Self { +82 Self { +83 amount_left: 0.0, +84 amount_right: 0.0, +85 amount_forward: 0.0, +86 amount_backward: 0.0, +87 amount_up: 0.0, +88 amount_down: 0.0, +89 rotate_horizontal: 0.0, +90 rotate_vertical: 0.0, +91 scroll: 0.0, +92 speed, +93 sensitivity, +94 active: true +95 } +96 } +97 +98 pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { +99 let amount = if state == ElementState::Pressed { +100 1.0 +101 } else { +102 0.0 +103 }; +104 let active = match key { +105 VirtualKeyCode::P => { +106 if state == ElementState::Pressed { +107 self.active = !self.active; +108 } +109 self.active +110 }, +111 _ => {self.active} +112 }; +113 if active { +114 match key { +115 VirtualKeyCode::W | VirtualKeyCode::Up => { +116 self.amount_forward = amount; +117 true +118 } +119 VirtualKeyCode::S | VirtualKeyCode::Down => { +120 self.amount_backward = amount; +121 true +122 } +123 VirtualKeyCode::A | VirtualKeyCode::Left => { +124 self.amount_left = amount; +125 true +126 } +127 VirtualKeyCode::D | VirtualKeyCode::Right => { +128 self.amount_right = amount; +129 true +130 } +131 VirtualKeyCode::Space => { +132 self.amount_up = amount; +133 true +134 } +135 VirtualKeyCode::LShift => { +136 self.amount_down = amount; +137 true +138 } +139 _ => false, +140 } +141 } else { +142 false +143 } +144 } +145 +146 pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) { +147 if self.active { +148 self.rotate_horizontal = -mouse_dx as f32; +149 self.rotate_vertical = mouse_dy as f32; +150 } +151 } +152 +153 pub fn update_camera(&mut self, camera: &mut Camera, dt: f32) { +154 +155 // Move forward/backward and left/right +156 let view_vector = Vector3::new( +157 (1.0 * camera.pitch.0.sin() * camera.yaw.0.sin()), +158 (1.0 * camera.pitch.0.cos()), +159 (1.0 * camera.pitch.0.sin() * camera.yaw.0.cos()), +160 ); +161 +162 // Offset the yaw 90 degrees and set the pitch to level for our +163 // right / left hand translation vectors +164 let offset = camera.yaw.0 + PI/2.0; +165 let pitch = PI/2.0; +166 let left_vector = Vector3::new( +167 (1.0 * pitch.sin() * offset.sin()), +168 (1.0 * pitch.cos()), +169 (1.0 * pitch.sin() * offset.cos()), +170 ); +171 +172 camera.position += view_vector * (self.amount_forward - self.amount_backward) * self.speed * dt; +173 camera.position += left_vector * (self.amount_left - self.amount_right) * self.speed * dt; +174 camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt; +175 +176 // Rotate +177 camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt; +178 camera.pitch += Rad(self.rotate_vertical) * self.sensitivity * dt; +179 +180 self.rotate_horizontal = 0.0; +181 self.rotate_vertical = 0.0; +182 +183 // Keep the camera's angle from going too high/low. +184 if camera.pitch < -Rad(0.001) { +185 camera.pitch = -Rad(0.001); +186 } else if camera.pitch > Rad(PI - 0.001) { +187 camera.pitch = Rad(PI - 0.001); +188 } +189 } +190 } +191+ + \ No newline at end of file diff --git a/exportToHTML/components.rs.html b/exportToHTML/components.rs.html new file mode 100644 index 0000000..040cf40 --- /dev/null +++ b/exportToHTML/components.rs.html @@ -0,0 +1,142 @@ + + +
1 use std::sync::Arc; +2 use std::time::{Duration, Instant}; +3 +4 use cgmath::{Deg, Euler}; +5 use rapier3d::dynamics::{RigidBody, RigidBodyHandle}; +6 use rapier3d::geometry::Collider as r3dCollider; +7 use rapier3d::geometry::ColliderHandle; +8 use wgpu::{BindGroup, Buffer, TextureView}; +9 +10 use crate::runtime::state::{TomlPositionDescription, TomlRotationDescription}; +11 use imgui::Ui; +12 +13 // a component is any type that is 'static, sized, send and sync +14 +15 pub struct ImguiWindow<'a, T> { +16 pub window: fn() -> imgui::Window<'a>, +17 pub func: fn(&Ui, Vec<&T>), +18 } +19 +20 #[derive(Clone, Copy, Debug, PartialEq)] +21 pub struct LoopState { +22 pub delta_time: Duration, +23 pub start_time: Instant, +24 pub step_size: f32, +25 } +26 +27 #[derive(Clone, Copy, Debug, PartialEq)] +28 pub struct Position { +29 pub x: f32, +30 pub y: f32, +31 pub z: f32, +32 pub rot: cgmath::Euler<Deg<f32>>, +33 } +34 +35 impl Default for Position { +36 fn default() -> Self { +37 Position { +38 x: 0.0, +39 y: 0.0, +40 z: 0.0, +41 rot: Euler { +42 x: Deg(0.0), +43 y: Deg(0.0), +44 z: Deg(0.0), +45 }, +46 } +47 } +48 } +49 +50 impl From<TomlPositionDescription> for Position { +51 fn from(pos: TomlPositionDescription) -> Self { +52 let euler = match pos.rot { +53 None => Euler { +54 x: Deg(0.0), +55 y: Deg(0.0), +56 z: Deg(0.0), +57 }, +58 Some(v) => Euler { +59 x: Deg(v.x), +60 y: Deg(v.y), +61 z: Deg(v.z), +62 }, +63 }; +64 Position { +65 x: pos.x, +66 y: pos.y, +67 z: pos.z, +68 rot: euler, +69 } +70 } +71 } +72 +73 impl From<Option<TomlPositionDescription>> for Position { +74 fn from(pos: Option<TomlPositionDescription>) -> Self { +75 match pos { +76 None => Position { +77 x: 0.0, +78 y: 0.0, +79 z: 0.0, +80 rot: Euler { +81 x: Deg(0.0), +82 y: Deg(0.0), +83 z: Deg(0.0), +84 }, +85 }, +86 Some(v) => Position::from(v), +87 } +88 } +89 } +90 +91 #[derive(Clone, Default, PartialEq, Eq, Hash, Copy, Debug)] +92 pub struct RangeCopy<Idx> { +93 pub start: Idx, +94 pub end: Idx, +95 } +96 +97 #[derive(Clone, Debug)] +98 pub struct Mesh { +99 pub index_buffer: Arc<Buffer>, +100 pub index_count: usize, +101 pub index_format: wgpu::IndexFormat, +102 pub vertex_buffer: Arc<Buffer>, +103 pub uniform_buffer: Arc<Buffer>, +104 pub bind_group: Arc<BindGroup>, +105 pub color: wgpu::Color, +106 } +107 +108 #[derive(Clone, Debug)] +109 pub struct Physics { +110 pub rigid_body: RigidBody, +111 pub rigid_body_handle: Option<RigidBodyHandle>, +112 } +113 +114 #[derive(Clone)] +115 pub struct Collider { +116 pub collider: r3dCollider, +117 pub collider_handle: Option<ColliderHandle>, +118 } +119+ + \ No newline at end of file diff --git a/exportToHTML/extended_winit_imgui_support.rs.html b/exportToHTML/extended_winit_imgui_support.rs.html new file mode 100644 index 0000000..d5618d2 --- /dev/null +++ b/exportToHTML/extended_winit_imgui_support.rs.html @@ -0,0 +1,1192 @@ + + +
1 //! This crate provides a winit-based backend platform for imgui_supp-rs. +2 //! +3 //! A backend platform handles window/input device events and manages their +4 //! state. +5 //! +6 //! # Using the library +7 //! +8 //! There are five things you need to do to use this library correctly: +9 //! +10 //! 1. Initialize a `WinitPlatform` instance +11 //! 2. Attach it to a winit `Window` +12 //! 3. Pass events to the platform (every frame) +13 //! 4. Call frame preparation callback (every frame) +14 //! 5. Call render preparation callback (every frame) +15 //! +16 //! ## Complete example for winit 0.20+ (without a renderer) +17 //! +18 //! ```rust,no_run,ignore +19 //! # // TODO: Remove ignore when only one winit version is used +20 //! use imgui_supp::Context; +21 //! use imgui_winit_support::{HiDpiMode, WinitPlatform}; +22 //! use std::time::Instant; +23 //! use winit::event::{Event, WindowEvent}; +24 //! use winit::event_loop::{ControlFlow, EventLoop}; +25 //! use winit::window::{Window}; +26 //! +27 //! let mut event_loop = EventLoop::new(); +28 //! let mut window = Window::new(&event_loop).unwrap(); +29 //! +30 //! let mut imgui_supp = Context::create(); +31 //! // configure imgui_supp-rs Context if necessary +32 //! +33 //! let mut platform = WinitPlatform::init(&mut imgui_supp); // step 1 +34 //! platform.attach_window(imgui_supp.io_mut(), &window, HiDpiMode::Default); // step 2 +35 //! +36 //! let mut last_frame = Instant::now(); +37 //! let mut run = true; +38 //! event_loop.run(move |event, _, control_flow| { +39 //! match event { +40 //! Event::NewEvents(_) => { +41 //! // other application-specific logic +42 //! last_frame = imgui_supp.io_mut().update_delta_time(last_frame); +43 //! }, +44 //! Event::MainEventsCleared => { +45 //! // other application-specific logic +46 //! platform.prepare_frame(imgui_supp.io_mut(), &window) // step 4 +47 //! .expect("Failed to prepare frame"); +48 //! window.request_redraw(); +49 //! } +50 //! Event::RedrawRequested(_) => { +51 //! let ui = imgui_supp.frame(); +52 //! // application-specific rendering *under the UI* +53 //! +54 //! // construct the UI +55 //! +56 //! platform.prepare_render(&ui, &window); // step 5 +57 //! // render the UI with a renderer +58 //! let draw_data = ui.render(); +59 //! // renderer.render(..., draw_data).expect("UI rendering failed"); +60 //! +61 //! // application-specific rendering *over the UI* +62 //! }, +63 //! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { +64 //! *control_flow = ControlFlow::Exit; +65 //! } +66 //! // other application-specific event handling +67 //! event => { +68 //! platform.handle_event(imgui_supp.io_mut(), &window, &event); // step 3 +69 //! // other application-specific event handling +70 //! } +71 //! } +72 //! }) +73 //! ``` +74 //! +75 //! ## `winit` versions and features. +76 //! +77 //! This crate has several features which control the version of winit which is +78 //! used. +79 //! +80 //! The following versions are supported, controlled by the listed feature. +81 //! +82 //! - The `winit-24` feature supports winit versions `0.24`. This is +83 //! on by default, so to use any other version you need to disable this crates +84 //! default features. +85 //! - The `winit-23` feature uses winit versions compatible with `0.23`. +86 //! - The `winit-22` feature uses winit versions compatible with `0.22`. +87 //! - The `winit-20` feature should support winit either `0.20` or winit `0.21`. +88 //! - The `winit-19` feature should support winits older than `0.19` (possibly +89 //! back to winit 0.16.*, but this isn't regularly tested and may not work). +90 //! +91 //! If multiple `winit-*` features are enabled, and it is a debug build (as +92 //! determined by `debug_assertions`), we will log a warning to stderr during +93 //! init. This can be disabled by either turning on the `no-warn-on-multiple` +94 //! feature, fixing the configuration, or disabling `debug_assertions`. +95 //! +96 //! Conversely, if no `winit-*` features are enabled, we will fail to compile. +97 //! This is not an issue generally, as by default we turn on `winit-24`. +98 //! +99 //! All of this is in attempt to preserve the additive nature of features (while +100 //! still helping users notice project configuration issues), however it's done +101 //! fairly weakly as our this crate's API isn't 100% identical across winit +102 //! versions. +103 //! +104 //! ### Using an older `winit` version +105 //! +106 //! To use an older version, you must configure `default-features = false` in +107 //! your `Cargo.toml`: +108 //! +109 //! ```toml +110 //! [dependencies.imgui_supp-winit-support] +111 //! version = "0.6" +112 //! features = ["winit-$YOUR_VERSION_HERE"] +113 //! default-features = false +114 //! ``` +115 //! +116 //! ### Old `winit` compatibility +117 //! +118 //! No guarantee is made on how long this crate will support legacy versions of +119 //! `winit`, but we'll try to follow these rules: +120 //! +121 //! - Versions which are still in widespread use in the ecosystem will be +122 //! supported while that is true (for example, 0.19 at the time of writing is +123 //! quite old, but used by the most recent version of several popular crates). +124 //! +125 //! - Versions which are not a significant maintenance burden will be supported +126 //! (for example, supporting versions older than winit 0.19 given that we +127 //! support 0.19). +128 //! +129 //! - Explicitly removing support for a feature-indicated version will be +130 //! considered a breaking change. +131 //! +132 //! - Changing the default feature to the new latest `winit` version is *not* a +133 //! breaking change. +134 +135 #[cfg(feature = "winit-24")] +136 use winit_24 as winit; +137 +138 #[cfg(all(not(feature = "winit-24"), feature = "winit-23"))] +139 use winit_23 as winit; +140 +141 #[cfg(all( +142 not(any(feature = "winit-24", feature = "winit-23")), +143 feature = "winit-22", +144 ))] +145 use winit_22 as winit; +146 +147 #[cfg(all( +148 not(any(feature = "winit-24", feature = "winit-23", feature = "winit-22")), +149 feature = "winit-20", +150 ))] +151 use winit_20 as winit; +152 +153 #[cfg(all( +154 not(any( +155 feature = "winit-24", +156 feature = "winit-23", +157 feature = "winit-22", +158 feature = "winit-20" +159 )), +160 feature = "winit-19", +161 ))] +162 use winit_19 as winit; +163 +164 use imgui::{self, BackendFlags, ConfigFlags, Context, ImString, Io, Key, Ui}; +165 use std::cell::Cell; +166 use std::cmp::Ordering; +167 use winit::dpi::{LogicalPosition, LogicalSize}; +168 +169 #[cfg(all( +170 not(any( +171 feature = "winit-24", +172 feature = "winit-23", +173 feature = "winit-22", +174 feature = "winit-20" +175 )), +176 feature = "winit-19", +177 ))] +178 use winit::{ +179 DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, MouseCursor, MouseScrollDelta, +180 TouchPhase, VirtualKeyCode, Window, WindowEvent, +181 }; +182 +183 #[cfg(any( +184 feature = "winit-20", +185 feature = "winit-22", +186 feature = "winit-23", +187 feature = "winit-24" +188 ))] +189 use winit::{ +190 error::ExternalError, +191 event::{ +192 DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, +193 VirtualKeyCode, WindowEvent, +194 }, +195 window::{CursorIcon as MouseCursor, Window}, +196 }; +197 use crate::owned_event::{OwnedEvent, OwnedWindowEvent}; +198 +199 // Ensure at least one is enabled +200 #[cfg(not(any( +201 feature = "winit-19", +202 feature = "winit-20", +203 feature = "winit-22", +204 feature = "winit-23", +205 feature = "winit-24", +206 )))] +207 compile_error!("Please enable at least one version of `winit` (see documentation for details)."); +208 +209 // FIXME(thom): make updading winit and adding a new feature less of a hassle here. +210 fn check_multiple_winits() { +211 use std::io::Write as _; +212 use std::sync::atomic::{AtomicBool, Ordering}; +213 // bail out for release builds or if we've been explicitly disabled. +214 if cfg!(any(not(debug_assertions), feature = "no-warn-on-multiple")) { +215 return; +216 } +217 let winits_enabled = cfg!(feature = "winit-24") as usize +218 + cfg!(feature = "winit-23") as usize +219 + cfg!(feature = "winit-22") as usize +220 + cfg!(feature = "winit-20") as usize +221 + cfg!(feature = "winit-19") as usize; +222 +223 // Only complain once even if we're called multiple times. +224 static COMPLAINED: AtomicBool = AtomicBool::new(false); +225 // Note that the `Ordering` basically doesn't matter here, but even if it +226 // did, `Relaxed` is still correct because we're only interested in the +227 // effects on a single atomic variable. +228 if winits_enabled <= 1 +229 || COMPLAINED +230 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) +231 .is_err() +232 { +233 return; +234 } +235 let mut err = Vec::with_capacity(512); +236 +237 // Log the complaint into a buffer first — in practice this is enough to +238 // ensure atomicity. +239 let _ = writeln!( +240 err, +241 "Warning (imgui_supp-winit-support): More than one `winit-*` version feature is enabled \ +242 (this likely indicates misconfiguration, see documentation for details)." +243 ); +244 let feats = [ +245 ("winit-24", cfg!(feature = "winit-24"), " (default)"), +246 ("winit-23", cfg!(feature = "winit-23"), ""), +247 ("winit-22", cfg!(feature = "winit-22"), ""), +248 ("winit-20", cfg!(feature = "winit-20"), ""), +249 ("winit-19", cfg!(feature = "winit-19"), ""), +250 ]; +251 for &(name, enabled, extra) in &feats { +252 if enabled { +253 let _ = writeln!(err, " `feature = {:?}` is enabled{}", name, extra); +254 } +255 } +256 if cfg!(feature = "winit-24") && winits_enabled == 2 { +257 let _ = writeln!( +258 err, +259 " Perhaps you are missing a `default-features = false`?", +260 ); +261 } +262 let _ = writeln!( +263 err, +264 " (Note: This warning is only present in debug builds, and \ +265 can be disabled using the \"no-warn-on-multiple\" feature)" +266 ); +267 let _ = std::io::stderr().write_all(&err); +268 } +269 +270 /// State of a single mouse button. Used so that we can detect cases where mouse +271 /// press and release occur on the same frame (seems surprisingly frequent on +272 /// macOS now...) +273 #[derive(Debug, Clone, Default)] +274 struct Button { +275 pressed_this_frame: Cell<bool>, +276 state: Cell<bool>, +277 } +278 +279 impl Button { +280 // we can use this in an array initializer, unlike `Default::default()` or a +281 // `const fn new()`. +282 #[allow(clippy::declare_interior_mutable_const)] +283 const INIT: Button = Self { +284 pressed_this_frame: Cell::new(false), +285 state: Cell::new(false), +286 }; +287 fn set(&self, pressed: bool) { +288 self.state.set(pressed); +289 if pressed { +290 self.pressed_this_frame.set(true); +291 } +292 } +293 fn get(&self) -> bool { +294 // If we got a press this frame, record it even if we got a release +295 // too — this way we don't drop mouse clicks where the release comes +296 // in on the same frame as the press. (This mirrors what Dear ImGUI +297 // seems to do in the `imgui_impl_*`) +298 self.pressed_this_frame.replace(false) || self.state.get() +299 } +300 } +301 +302 /// winit backend platform state +303 #[derive(Debug)] +304 pub struct WinitPlatform { +305 hidpi_mode: ActiveHiDpiMode, +306 hidpi_factor: f64, +307 cursor_cache: Option<CursorSettings>, +308 mouse_buttons: [Button; 5], +309 } +310 +311 #[derive(Debug, Copy, Clone, Eq, PartialEq)] +312 struct CursorSettings { +313 cursor: Option<imgui::MouseCursor>, +314 draw_cursor: bool, +315 } +316 +317 fn to_winit_cursor(cursor: imgui::MouseCursor) -> MouseCursor { +318 match cursor { +319 imgui::MouseCursor::Arrow => MouseCursor::Default, +320 imgui::MouseCursor::TextInput => MouseCursor::Text, +321 imgui::MouseCursor::ResizeAll => MouseCursor::Move, +322 imgui::MouseCursor::ResizeNS => MouseCursor::NsResize, +323 imgui::MouseCursor::ResizeEW => MouseCursor::EwResize, +324 imgui::MouseCursor::ResizeNESW => MouseCursor::NeswResize, +325 imgui::MouseCursor::ResizeNWSE => MouseCursor::NwseResize, +326 imgui::MouseCursor::Hand => MouseCursor::Hand, +327 imgui::MouseCursor::NotAllowed => MouseCursor::NotAllowed, +328 } +329 } +330 +331 impl CursorSettings { +332 #[cfg(all( +333 not(any( +334 feature = "winit-24", +335 feature = "winit-23", +336 feature = "winit-22", +337 feature = "winit-20" +338 )), +339 feature = "winit-19", +340 ))] +341 fn apply(&self, window: &Window) { +342 match self.cursor { +343 Some(mouse_cursor) if !self.draw_cursor => { +344 window.hide_cursor(false); +345 window.set_cursor(to_winit_cursor(mouse_cursor)); +346 } +347 _ => window.hide_cursor(true), +348 } +349 } +350 #[cfg(any( +351 feature = "winit-20", +352 feature = "winit-22", +353 feature = "winit-23", +354 feature = "winit-24" +355 ))] +356 fn apply(&self, window: &Window) { +357 match self.cursor { +358 Some(mouse_cursor) if !self.draw_cursor => { +359 window.set_cursor_visible(true); +360 window.set_cursor_icon(to_winit_cursor(mouse_cursor)); +361 } +362 _ => window.set_cursor_visible(false), +363 } +364 } +365 } +366 +367 #[derive(Copy, Clone, Debug, PartialEq)] +368 enum ActiveHiDpiMode { +369 Default, +370 Rounded, +371 Locked, +372 } +373 +374 /// DPI factor handling mode. +375 /// +376 /// Applications that use imgui_supp-rs might want to customize the used DPI factor and not use +377 /// directly the value coming from winit. +378 /// +379 /// **Note: if you use a mode other than default and the DPI factor is adjusted, winit and imgui_supp-rs +380 /// will use different logical coordinates, so be careful if you pass around logical size or +381 /// position values.** +382 #[derive(Copy, Clone, Debug, PartialEq)] +383 pub enum HiDpiMode { +384 /// The DPI factor from winit is used directly without adjustment +385 Default, +386 /// The DPI factor from winit is rounded to an integer value. +387 /// +388 /// This prevents the user interface from becoming blurry with non-integer scaling. +389 Rounded, +390 /// The DPI factor from winit is ignored, and the included value is used instead. +391 /// +392 /// This is useful if you want to force some DPI factor (e.g. 1.0) and not care about the value +393 /// coming from winit. +394 Locked(f64), +395 } +396 +397 impl HiDpiMode { +398 fn apply(&self, hidpi_factor: f64) -> (ActiveHiDpiMode, f64) { +399 match *self { +400 HiDpiMode::Default => (ActiveHiDpiMode::Default, hidpi_factor), +401 HiDpiMode::Rounded => (ActiveHiDpiMode::Rounded, hidpi_factor.round()), +402 HiDpiMode::Locked(value) => (ActiveHiDpiMode::Locked, value), +403 } +404 } +405 } +406 +407 impl WinitPlatform { +408 /// Initializes a winit platform instance and configures imgui_supp. +409 /// +410 /// This function configures imgui_supp-rs in the following ways: +411 /// +412 /// * backend flags are updated +413 /// * keys are configured +414 /// * platform name is set +415 pub fn init(imgui: &mut Context) -> WinitPlatform { +416 // noop in non-debug builds, if disabled, or if called a second time. +417 check_multiple_winits(); +418 let io = imgui.io_mut(); +419 io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS); +420 io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS); +421 io[Key::Tab] = VirtualKeyCode::Tab as _; +422 io[Key::LeftArrow] = VirtualKeyCode::Left as _; +423 io[Key::RightArrow] = VirtualKeyCode::Right as _; +424 io[Key::UpArrow] = VirtualKeyCode::Up as _; +425 io[Key::DownArrow] = VirtualKeyCode::Down as _; +426 io[Key::PageUp] = VirtualKeyCode::PageUp as _; +427 io[Key::PageDown] = VirtualKeyCode::PageDown as _; +428 io[Key::Home] = VirtualKeyCode::Home as _; +429 io[Key::End] = VirtualKeyCode::End as _; +430 io[Key::Insert] = VirtualKeyCode::Insert as _; +431 io[Key::Delete] = VirtualKeyCode::Delete as _; +432 io[Key::Backspace] = VirtualKeyCode::Back as _; +433 io[Key::Space] = VirtualKeyCode::Space as _; +434 io[Key::Enter] = VirtualKeyCode::Return as _; +435 io[Key::Escape] = VirtualKeyCode::Escape as _; +436 io[Key::KeyPadEnter] = VirtualKeyCode::NumpadEnter as _; +437 io[Key::A] = VirtualKeyCode::A as _; +438 io[Key::C] = VirtualKeyCode::C as _; +439 io[Key::V] = VirtualKeyCode::V as _; +440 io[Key::X] = VirtualKeyCode::X as _; +441 io[Key::Y] = VirtualKeyCode::Y as _; +442 io[Key::Z] = VirtualKeyCode::Z as _; +443 imgui.set_platform_name(Some(ImString::from(format!( +444 "imgui_supp-winit-support {}", +445 env!("CARGO_PKG_VERSION") +446 )))); +447 WinitPlatform { +448 hidpi_mode: ActiveHiDpiMode::Default, +449 hidpi_factor: 1.0, +450 cursor_cache: None, +451 mouse_buttons: [Button::INIT; 5], +452 } +453 } +454 /// Attaches the platform instance to a winit window. +455 /// +456 /// This function configures imgui_supp-rs in the following ways: +457 /// +458 /// * framebuffer scale (= DPI factor) is set +459 /// * display size is set +460 #[cfg(all( +461 not(any( +462 feature = "winit-24", +463 feature = "winit-23", +464 feature = "winit-22", +465 feature = "winit-20" +466 )), +467 feature = "winit-19", +468 ))] +469 pub fn attach_window(&mut self, io: &mut Io, window: &Window, hidpi_mode: HiDpiMode) { +470 let (hidpi_mode, hidpi_factor) = hidpi_mode.apply(window.get_hidpi_factor()); +471 self.hidpi_mode = hidpi_mode; +472 self.hidpi_factor = hidpi_factor; +473 io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32]; +474 if let Some(logical_size) = window.get_inner_size() { +475 let logical_size = self.scale_size_from_winit(window, logical_size); +476 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +477 } +478 } +479 /// Attaches the platform instance to a winit window. +480 /// +481 /// This function configures imgui_supp-rs in the following ways: +482 /// +483 /// * framebuffer scale (= DPI factor) is set +484 /// * display size is set +485 #[cfg(any( +486 feature = "winit-20", +487 feature = "winit-22", +488 feature = "winit-23", +489 feature = "winit-24" +490 ))] +491 pub fn attach_window(&mut self, io: &mut Io, window: &Window, hidpi_mode: HiDpiMode) { +492 let (hidpi_mode, hidpi_factor) = hidpi_mode.apply(window.scale_factor()); +493 self.hidpi_mode = hidpi_mode; +494 self.hidpi_factor = hidpi_factor; +495 io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32]; +496 let logical_size = window.inner_size().to_logical(hidpi_factor); +497 let logical_size = self.scale_size_from_winit(window, logical_size); +498 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +499 } +500 /// Returns the current DPI factor. +501 /// +502 /// The value might not be the same as the winit DPI factor (depends on the used DPI mode) +503 pub fn hidpi_factor(&self) -> f64 { +504 self.hidpi_factor +505 } +506 /// Scales a logical size coming from winit using the current DPI mode. +507 /// +508 /// This utility function is useful if you are using a DPI mode other than default, and want +509 /// your application to use the same logical coordinates as imgui_supp-rs. +510 #[cfg(all( +511 not(any( +512 feature = "winit-24", +513 feature = "winit-23", +514 feature = "winit-22", +515 feature = "winit-20" +516 )), +517 feature = "winit-19", +518 ))] +519 pub fn scale_size_from_winit(&self, window: &Window, logical_size: LogicalSize) -> LogicalSize { +520 match self.hidpi_mode { +521 ActiveHiDpiMode::Default => logical_size, +522 _ => logical_size +523 .to_physical(window.get_hidpi_factor()) +524 .to_logical(self.hidpi_factor), +525 } +526 } +527 /// Scales a logical size coming from winit using the current DPI mode. +528 /// +529 /// This utility function is useful if you are using a DPI mode other than default, and want +530 /// your application to use the same logical coordinates as imgui_supp-rs. +531 #[cfg(any( +532 feature = "winit-20", +533 feature = "winit-22", +534 feature = "winit-23", +535 feature = "winit-24" +536 ))] +537 pub fn scale_size_from_winit( +538 &self, +539 window: &Window, +540 logical_size: LogicalSize<f64>, +541 ) -> LogicalSize<f64> { +542 match self.hidpi_mode { +543 ActiveHiDpiMode::Default => logical_size, +544 _ => logical_size +545 .to_physical::<f64>(window.scale_factor()) +546 .to_logical(self.hidpi_factor), +547 } +548 } +549 /// Scales a logical position coming from winit using the current DPI mode. +550 /// +551 /// This utility function is useful if you are using a DPI mode other than default, and want +552 /// your application to use the same logical coordinates as imgui_supp-rs. +553 #[cfg(all( +554 not(any( +555 feature = "winit-24", +556 feature = "winit-23", +557 feature = "winit-22", +558 feature = "winit-20" +559 )), +560 feature = "winit-19", +561 ))] +562 pub fn scale_pos_from_winit( +563 &self, +564 window: &Window, +565 logical_pos: LogicalPosition, +566 ) -> LogicalPosition { +567 match self.hidpi_mode { +568 ActiveHiDpiMode::Default => logical_pos, +569 _ => logical_pos +570 .to_physical(window.get_hidpi_factor()) +571 .to_logical(self.hidpi_factor), +572 } +573 } +574 /// Scales a logical position coming from winit using the current DPI mode. +575 /// +576 /// This utility function is useful if you are using a DPI mode other than default, and want +577 /// your application to use the same logical coordinates as imgui_supp-rs. +578 #[cfg(any( +579 feature = "winit-20", +580 feature = "winit-22", +581 feature = "winit-23", +582 feature = "winit-24" +583 ))] +584 pub fn scale_pos_from_winit( +585 &self, +586 window: &Window, +587 logical_pos: LogicalPosition<f64>, +588 ) -> LogicalPosition<f64> { +589 match self.hidpi_mode { +590 ActiveHiDpiMode::Default => logical_pos, +591 _ => logical_pos +592 .to_physical::<f64>(window.scale_factor()) +593 .to_logical(self.hidpi_factor), +594 } +595 } +596 /// Scales a logical position for winit using the current DPI mode. +597 /// +598 /// This utility function is useful if you are using a DPI mode other than default, and want +599 /// your application to use the same logical coordinates as imgui_supp-rs. +600 #[cfg(all( +601 not(any( +602 feature = "winit-24", +603 feature = "winit-23", +604 feature = "winit-22", +605 feature = "winit-20" +606 )), +607 feature = "winit-19", +608 ))] +609 pub fn scale_pos_for_winit( +610 &self, +611 window: &Window, +612 logical_pos: LogicalPosition, +613 ) -> LogicalPosition { +614 match self.hidpi_mode { +615 ActiveHiDpiMode::Default => logical_pos, +616 _ => logical_pos +617 .to_physical(self.hidpi_factor) +618 .to_logical(window.get_hidpi_factor()), +619 } +620 } +621 /// Scales a logical position for winit using the current DPI mode. +622 /// +623 /// This utility function is useful if you are using a DPI mode other than default, and want +624 /// your application to use the same logical coordinates as imgui_supp-rs. +625 #[cfg(any( +626 feature = "winit-20", +627 feature = "winit-22", +628 feature = "winit-23", +629 feature = "winit-24" +630 ))] +631 pub fn scale_pos_for_winit( +632 &self, +633 window: &Window, +634 logical_pos: LogicalPosition<f64>, +635 ) -> LogicalPosition<f64> { +636 match self.hidpi_mode { +637 ActiveHiDpiMode::Default => logical_pos, +638 _ => logical_pos +639 .to_physical::<f64>(self.hidpi_factor) +640 .to_logical(window.scale_factor()), +641 } +642 } +643 /// Handles a winit event. +644 /// +645 /// This function performs the following actions (depends on the event): +646 /// +647 /// * window size / dpi factor changes are applied +648 /// * keyboard state is updated +649 /// * mouse state is updated +650 #[cfg(all( +651 not(any( +652 feature = "winit-24", +653 feature = "winit-23", +654 feature = "winit-22", +655 feature = "winit-20" +656 )), +657 feature = "winit-19", +658 ))] +659 pub fn handle_event(&mut self, io: &mut Io, window: &Window, event: &Event) { +660 match *event { +661 Event::WindowEvent { +662 window_id, +663 ref event, +664 } if window_id == window.id() => { +665 self.handle_window_event(io, window, event); +666 } +667 // Track key release events outside our window. If we don't do this, +668 // we might never see the release event if some other window gets focus. +669 Event::DeviceEvent { +670 event: +671 DeviceEvent::Key(KeyboardInput { +672 state: ElementState::Released, +673 virtual_keycode: Some(key), +674 .. +675 }), +676 .. +677 } => { +678 io.keys_down[key as usize] = false; +679 match key { +680 VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = false, +681 VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = false, +682 VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = false, +683 VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = false, +684 _ => (), +685 } +686 } +687 _ => (), +688 } +689 } +690 /// Handles a winit event. +691 /// +692 /// This function performs the following actions (depends on the event): +693 /// +694 /// * window size / dpi factor changes are applied +695 /// * keyboard state is updated +696 /// * mouse state is updated +697 #[cfg(all( +698 not(any(feature = "winit-24", feature = "winit-23", feature = "winit-22")), +699 feature = "winit-20", +700 ))] +701 pub fn handle_event<T>(&mut self, io: &mut Io, window: &Window, event: &Event<T>) { +702 match *event { +703 Event::WindowEvent { +704 window_id, +705 ref event, +706 } if window_id == window.id() => { +707 self.handle_window_event(io, window, event); +708 } +709 // Track key release events outside our window. If we don't do this, +710 // we might never see the release event if some other window gets focus. +711 Event::DeviceEvent { +712 event: +713 DeviceEvent::Key(KeyboardInput { +714 state: ElementState::Released, +715 virtual_keycode: Some(key), +716 .. +717 }), +718 .. +719 } => { +720 io.keys_down[key as usize] = false; +721 } +722 +723 // We need to track modifiers separately because some system like macOS, will +724 // not reliably send modifier states during certain events like ScreenCapture. +725 // Gotta let the people show off their pretty imgui_supp widgets! +726 Event::DeviceEvent { +727 event: DeviceEvent::ModifiersChanged(modifiers), +728 .. +729 } => { +730 io.key_shift = modifiers.shift(); +731 io.key_ctrl = modifiers.ctrl(); +732 io.key_alt = modifiers.alt(); +733 io.key_super = modifiers.logo(); +734 } +735 _ => (), +736 } +737 } +738 /// Handles a winit event. +739 /// +740 /// This function performs the following actions (depends on the event): +741 /// +742 /// * window size / dpi factor changes are applied +743 /// * keyboard state is updated +744 /// * mouse state is updated +745 #[cfg(any(feature = "winit-22", feature = "winit-23", feature = "winit-24"))] +746 pub fn handle_event<T>(&mut self, io: &mut Io, window: &Window, event: &OwnedEvent<T>) { +747 match *event { +748 OwnedEvent::WindowEvent { +749 window_id, +750 ref event, +751 } if window_id == window.id() => { +752 // We need to track modifiers separately because some system like macOS, will +753 // not reliably send modifier states during certain events like ScreenCapture. +754 // Gotta let the people show off their pretty imgui_supp widgets! +755 if let OwnedWindowEvent::ModifiersChanged(modifiers) = event { +756 io.key_shift = modifiers.shift(); +757 io.key_ctrl = modifiers.ctrl(); +758 io.key_alt = modifiers.alt(); +759 io.key_super = modifiers.logo(); +760 } +761 +762 self.handle_window_event(io, window, event); +763 } +764 // Track key release events outside our window. If we don't do this, +765 // we might never see the release event if some other window gets focus. +766 OwnedEvent::DeviceEvent { +767 event: +768 DeviceEvent::Key(KeyboardInput { +769 state: ElementState::Released, +770 virtual_keycode: Some(key), +771 .. +772 }), +773 .. +774 } => { +775 io.keys_down[key as usize] = false; +776 } +777 _ => (), +778 } +779 } +780 #[cfg(all( +781 not(any( +782 feature = "winit-24", +783 feature = "winit-23", +784 feature = "winit-22", +785 feature = "winit-20" +786 )), +787 feature = "winit-19", +788 ))] +789 fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) { +790 match *event { +791 WindowEvent::Resized(logical_size) => { +792 let logical_size = self.scale_size_from_winit(window, logical_size); +793 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +794 } +795 WindowEvent::HiDpiFactorChanged(scale) => { +796 let hidpi_factor = match self.hidpi_mode { +797 ActiveHiDpiMode::Default => scale, +798 ActiveHiDpiMode::Rounded => scale.round(), +799 _ => return, +800 }; +801 // Mouse position needs to be changed while we still have both the old and the new +802 // values +803 if io.mouse_pos[0].is_finite() && io.mouse_pos[1].is_finite() { +804 io.mouse_pos = [ +805 io.mouse_pos[0] * (hidpi_factor / self.hidpi_factor) as f32, +806 io.mouse_pos[1] * (hidpi_factor / self.hidpi_factor) as f32, +807 ]; +808 } +809 self.hidpi_factor = hidpi_factor; +810 io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32]; +811 // Window size might change too if we are using DPI rounding +812 if let Some(logical_size) = window.get_inner_size() { +813 let logical_size = self.scale_size_from_winit(window, logical_size); +814 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +815 } +816 } +817 WindowEvent::KeyboardInput { +818 input: +819 KeyboardInput { +820 virtual_keycode: Some(key), +821 state, +822 .. +823 }, +824 .. +825 } => { +826 io.keys_down[key as usize] = state == ElementState::Pressed; +827 } +828 WindowEvent::ReceivedCharacter(ch) => { +829 // Exclude the backspace key ('\u{7f}'). Otherwise we will insert this char and then +830 // delete it. +831 if ch != '\u{7f}' { +832 io.add_input_character(ch) +833 } +834 } +835 WindowEvent::CursorMoved { position, .. } => { +836 let position = self.scale_pos_from_winit(window, position); +837 io.mouse_pos = [position.x as f32, position.y as f32]; +838 } +839 WindowEvent::MouseWheel { +840 delta, +841 phase: TouchPhase::Moved, +842 .. +843 } => match delta { +844 MouseScrollDelta::LineDelta(h, v) => { +845 io.mouse_wheel_h = h; +846 io.mouse_wheel = v; +847 } +848 MouseScrollDelta::PixelDelta(pos) => { +849 match pos.x.partial_cmp(&0.0) { +850 Some(Ordering::Greater) => io.mouse_wheel_h += 1.0, +851 Some(Ordering::Less) => io.mouse_wheel_h -= 1.0, +852 _ => (), +853 } +854 match pos.y.partial_cmp(&0.0) { +855 Some(Ordering::Greater) => io.mouse_wheel += 1.0, +856 Some(Ordering::Less) => io.mouse_wheel -= 1.0, +857 _ => (), +858 } +859 } +860 }, +861 WindowEvent::MouseInput { state, button, .. } => { +862 let pressed = state == ElementState::Pressed; +863 match button { +864 MouseButton::Left => self.mouse_buttons[0].set(pressed), +865 MouseButton::Right => self.mouse_buttons[1].set(pressed), +866 MouseButton::Middle => self.mouse_buttons[2].set(pressed), +867 MouseButton::Other(idx @ 0..=4) => { +868 self.mouse_buttons[idx as usize].set(pressed) +869 } +870 _ => (), +871 } +872 } +873 _ => (), +874 } +875 } +876 #[cfg(all( +877 not(any(feature = "winit-23", feature = "winit-24")), +878 any(feature = "winit-20", feature = "winit-22") +879 ))] +880 fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &WindowEvent) { +881 match *event { +882 WindowEvent::Resized(physical_size) => { +883 let logical_size = physical_size.to_logical(window.scale_factor()); +884 let logical_size = self.scale_size_from_winit(window, logical_size); +885 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +886 } +887 WindowEvent::ScaleFactorChanged { scale_factor, .. } => { +888 let hidpi_factor = match self.hidpi_mode { +889 ActiveHiDpiMode::Default => scale_factor, +890 ActiveHiDpiMode::Rounded => scale_factor.round(), +891 _ => return, +892 }; +893 // Mouse position needs to be changed while we still have both the old and the new +894 // values +895 if io.mouse_pos[0].is_finite() && io.mouse_pos[1].is_finite() { +896 io.mouse_pos = [ +897 io.mouse_pos[0] * (hidpi_factor / self.hidpi_factor) as f32, +898 io.mouse_pos[1] * (hidpi_factor / self.hidpi_factor) as f32, +899 ]; +900 } +901 self.hidpi_factor = hidpi_factor; +902 io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32]; +903 // Window size might change too if we are using DPI rounding +904 let logical_size = window.inner_size().to_logical(scale_factor); +905 let logical_size = self.scale_size_from_winit(window, logical_size); +906 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +907 } +908 WindowEvent::KeyboardInput { +909 input: +910 KeyboardInput { +911 virtual_keycode: Some(key), +912 state, +913 .. +914 }, +915 .. +916 } => { +917 let pressed = state == ElementState::Pressed; +918 io.keys_down[key as usize] = pressed; +919 +920 // This is a bit redundant here, but we'll leave it in. The OS occasionally +921 // fails to send modifiers keys, but it doesn't seem to send false-positives, +922 // so double checking isn't terrible in case some system *doesn't* send +923 // device events sometimes. +924 match key { +925 VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, +926 VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed, +927 VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, +928 VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, +929 _ => (), +930 } +931 } +932 WindowEvent::ReceivedCharacter(ch) => { +933 // Exclude the backspace key ('\u{7f}'). Otherwise we will insert this char and then +934 // delete it. +935 if ch != '\u{7f}' { +936 io.add_input_character(ch) +937 } +938 } +939 WindowEvent::CursorMoved { position, .. } => { +940 let position = position.to_logical(window.scale_factor()); +941 let position = self.scale_pos_from_winit(window, position); +942 io.mouse_pos = [position.x as f32, position.y as f32]; +943 } +944 WindowEvent::MouseWheel { +945 delta, +946 phase: TouchPhase::Moved, +947 .. +948 } => match delta { +949 MouseScrollDelta::LineDelta(h, v) => { +950 io.mouse_wheel_h = h; +951 io.mouse_wheel = v; +952 } +953 MouseScrollDelta::PixelDelta(pos) => { +954 match pos.x.partial_cmp(&0.0) { +955 Some(Ordering::Greater) => io.mouse_wheel_h += 1.0, +956 Some(Ordering::Less) => io.mouse_wheel_h -= 1.0, +957 _ => (), +958 } +959 match pos.y.partial_cmp(&0.0) { +960 Some(Ordering::Greater) => io.mouse_wheel += 1.0, +961 Some(Ordering::Less) => io.mouse_wheel -= 1.0, +962 _ => (), +963 } +964 } +965 }, +966 WindowEvent::MouseInput { state, button, .. } => { +967 let pressed = state == ElementState::Pressed; +968 match button { +969 MouseButton::Left => self.mouse_buttons[0].set(pressed), +970 MouseButton::Right => self.mouse_buttons[1].set(pressed), +971 MouseButton::Middle => self.mouse_buttons[2].set(pressed), +972 MouseButton::Other(idx @ 0..=4) => { +973 self.mouse_buttons[idx as usize].set(pressed) +974 } +975 _ => (), +976 } +977 } +978 _ => (), +979 } +980 } +981 +982 #[cfg(any(feature = "winit-23", feature = "winit-24"))] +983 fn handle_window_event(&mut self, io: &mut Io, window: &Window, event: &OwnedWindowEvent) { +984 match *event { +985 OwnedWindowEvent::Resized(physical_size) => { +986 let logical_size = physical_size.to_logical(window.scale_factor()); +987 let logical_size = self.scale_size_from_winit(window, logical_size); +988 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +989 } +990 OwnedWindowEvent::ScaleFactorChanged { scale_factor, .. } => { +991 let hidpi_factor = match self.hidpi_mode { +992 ActiveHiDpiMode::Default => scale_factor, +993 ActiveHiDpiMode::Rounded => scale_factor.round(), +994 _ => return, +995 }; +996 // Mouse position needs to be changed while we still have both the old and the new +997 // values +998 if io.mouse_pos[0].is_finite() && io.mouse_pos[1].is_finite() { +999 io.mouse_pos = [ +1000 io.mouse_pos[0] * (hidpi_factor / self.hidpi_factor) as f32, +1001 io.mouse_pos[1] * (hidpi_factor / self.hidpi_factor) as f32, +1002 ]; +1003 } +1004 self.hidpi_factor = hidpi_factor; +1005 io.display_framebuffer_scale = [hidpi_factor as f32, hidpi_factor as f32]; +1006 // Window size might change too if we are using DPI rounding +1007 let logical_size = window.inner_size().to_logical(scale_factor); +1008 let logical_size = self.scale_size_from_winit(window, logical_size); +1009 io.display_size = [logical_size.width as f32, logical_size.height as f32]; +1010 } +1011 OwnedWindowEvent::KeyboardInput { +1012 input: +1013 KeyboardInput { +1014 virtual_keycode: Some(key), +1015 state, +1016 .. +1017 }, +1018 .. +1019 } => { +1020 let pressed = state == ElementState::Pressed; +1021 io.keys_down[key as usize] = pressed; +1022 +1023 // This is a bit redundant here, but we'll leave it in. The OS occasionally +1024 // fails to send modifiers keys, but it doesn't seem to send false-positives, +1025 // so double checking isn't terrible in case some system *doesn't* send +1026 // device events sometimes. +1027 match key { +1028 VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, +1029 VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed, +1030 VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, +1031 VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, +1032 _ => (), +1033 } +1034 } +1035 OwnedWindowEvent::ReceivedCharacter(ch) => { +1036 // Exclude the backspace key ('\u{7f}'). Otherwise we will insert this char and then +1037 // delete it. +1038 if ch != '\u{7f}' { +1039 io.add_input_character(ch) +1040 } +1041 } +1042 OwnedWindowEvent::CursorMoved { position, .. } => { +1043 let position = position.to_logical(window.scale_factor()); +1044 let position = self.scale_pos_from_winit(window, position); +1045 io.mouse_pos = [position.x as f32, position.y as f32]; +1046 } +1047 OwnedWindowEvent::MouseWheel { +1048 delta, +1049 phase: TouchPhase::Moved, +1050 .. +1051 } => match delta { +1052 MouseScrollDelta::LineDelta(h, v) => { +1053 io.mouse_wheel_h = h; +1054 io.mouse_wheel = v; +1055 } +1056 MouseScrollDelta::PixelDelta(pos) => { +1057 let pos = pos.to_logical::<f64>(self.hidpi_factor); +1058 match pos.x.partial_cmp(&0.0) { +1059 Some(Ordering::Greater) => io.mouse_wheel_h += 1.0, +1060 Some(Ordering::Less) => io.mouse_wheel_h -= 1.0, +1061 _ => (), +1062 } +1063 match pos.y.partial_cmp(&0.0) { +1064 Some(Ordering::Greater) => io.mouse_wheel += 1.0, +1065 Some(Ordering::Less) => io.mouse_wheel -= 1.0, +1066 _ => (), +1067 } +1068 } +1069 }, +1070 OwnedWindowEvent::MouseInput { state, button, .. } => { +1071 let pressed = state == ElementState::Pressed; +1072 match button { +1073 MouseButton::Left => self.mouse_buttons[0].set(pressed), +1074 MouseButton::Right => self.mouse_buttons[1].set(pressed), +1075 MouseButton::Middle => self.mouse_buttons[2].set(pressed), +1076 MouseButton::Other(idx @ 0..=4) => { +1077 self.mouse_buttons[idx as usize].set(pressed) +1078 } +1079 _ => (), +1080 } +1081 } +1082 _ => (), +1083 } +1084 } +1085 /// Frame preparation callback. +1086 /// +1087 /// Call this before calling the imgui_supp-rs context `frame` function. +1088 /// This function performs the following actions: +1089 /// +1090 /// * mouse cursor is repositioned (if requested by imgui_supp-rs) +1091 #[cfg(all( +1092 not(any( +1093 feature = "winit-24", +1094 feature = "winit-23", +1095 feature = "winit-22", +1096 feature = "winit-20" +1097 )), +1098 feature = "winit-19", +1099 ))] +1100 pub fn prepare_frame(&self, io: &mut Io, window: &Window) -> Result<(), String> { +1101 self.copy_mouse_to_io(&mut io.mouse_down); +1102 if io.want_set_mouse_pos { +1103 let logical_pos = self.scale_pos_for_winit( +1104 window, +1105 LogicalPosition::new(f64::from(io.mouse_pos[0]), f64::from(io.mouse_pos[1])), +1106 ); +1107 window.set_cursor_position(logical_pos) +1108 } else { +1109 Ok(()) +1110 } +1111 } +1112 /// Frame preparation callback. +1113 /// +1114 /// Call this before calling the imgui_supp-rs context `frame` function. +1115 /// This function performs the following actions: +1116 /// +1117 /// * mouse cursor is repositioned (if requested by imgui_supp-rs) +1118 #[cfg(any( +1119 feature = "winit-20", +1120 feature = "winit-22", +1121 feature = "winit-23", +1122 feature = "winit-24" +1123 ))] +1124 pub fn prepare_frame(&self, io: &mut Io, window: &Window) -> Result<(), ExternalError> { +1125 self.copy_mouse_to_io(&mut io.mouse_down); +1126 if io.want_set_mouse_pos { +1127 let logical_pos = self.scale_pos_for_winit( +1128 window, +1129 LogicalPosition::new(f64::from(io.mouse_pos[0]), f64::from(io.mouse_pos[1])), +1130 ); +1131 window.set_cursor_position(logical_pos) +1132 } else { +1133 Ok(()) +1134 } +1135 } +1136 +1137 fn copy_mouse_to_io(&self, io_mouse_down: &mut [bool]) { +1138 for (io_down, button) in io_mouse_down.iter_mut().zip(&self.mouse_buttons) { +1139 *io_down = button.get(); +1140 } +1141 } +1142 +1143 /// Render preparation callback. +1144 /// +1145 /// Call this before calling the imgui_supp-rs UI `render_with`/`render` function. +1146 /// This function performs the following actions: +1147 /// +1148 /// * mouse cursor is changed and/or hidden (if requested by imgui_supp-rs) +1149 pub fn prepare_render(&mut self, ui: &Ui, window: &Window) { +1150 let io = ui.io(); +1151 if !io +1152 .config_flags +1153 .contains(ConfigFlags::NO_MOUSE_CURSOR_CHANGE) +1154 { +1155 let cursor = CursorSettings { +1156 cursor: ui.mouse_cursor(), +1157 draw_cursor: io.mouse_draw_cursor, +1158 }; +1159 if self.cursor_cache != Some(cursor) { +1160 cursor.apply(window); +1161 self.cursor_cache = Some(cursor); +1162 } +1163 } +1164 } +1165 } +1166+ + \ No newline at end of file diff --git a/exportToHTML/geometry.rs.html b/exportToHTML/geometry.rs.html new file mode 100644 index 0000000..612b920 --- /dev/null +++ b/exportToHTML/geometry.rs.html @@ -0,0 +1,164 @@ + + +
1 use bytemuck::{Pod, Zeroable}; +2 use nalgebra::Vector4; +3 use rapier3d::parry::math::Point; +4 use tobj::{LoadError, Model, Material}; +5 +6 +7 #[repr(C)] +8 #[derive(Clone, Copy, Debug)] +9 pub struct Vertex { +10 pos: [f32; 4], +11 normal: [f32; 4], +12 uv: [f32; 2], +13 } +14 +15 impl Vertex { +16 pub fn position(&self) -> Point<f32> { +17 Point::<f32>::new(self.pos[0], self.pos[1], self.pos[2]) +18 } +19 pub fn from(pos: [f32; 3], nor: [f32; 3], uv: [f32; 2]) -> Vertex { +20 Vertex { +21 pos: [pos[0], pos[1], pos[2], 1.0], +22 normal: [nor[0], nor[1], nor[2], 0.0], +23 uv: [uv[0], uv[1]], +24 } +25 } +26 } +27 +28 unsafe impl Pod for Vertex {} +29 unsafe impl Zeroable for Vertex {} +30 +31 #[derive(Clone, Debug)] +32 pub struct RawMesh { +33 pub vertices: Vec<Vertex>, +34 pub indices: Vec<[u32; 3]>, +35 } +36 +37 +38 /// We use meshes in a few different places. To keep things simple, we return +39 /// the most basic, direct-to-memory version. If something fancy needs to be done +40 /// with it, the fancy stays there +41 pub fn load_obj(obj_path: &str) -> Result<RawMesh, String> { +42 +43 log::info!("Loading object {}", obj_path); +44 +45 // Is there no better way to translate error messages? +46 let (models, materials) = match tobj::load_obj(obj_path, true) { +47 Ok((a, b)) => {Ok((a, b))} +48 Err(load_error) => {Err(load_error.to_string())} +49 }?; +50 +51 // println!("# of models: {}", models.len()); +52 // println!("# of materials: {}", materials.len()); +53 // println!("{:?}", materials); +54 +55 let mut index_data: Vec<[u32; 3]> = Vec::new(); +56 let mut vertex_data = Vec::new(); +57 +58 for model in models { +59 let mesh = &model.mesh; +60 +61 // Cycle through the faces and chunk out the indices +62 let mut next_face = 0; +63 for f in 0..mesh.num_face_indices.len() { +64 // calculate the next chunk +65 let end = next_face + mesh.num_face_indices[f] as usize; +66 let face_indices: Vec<_> = mesh.indices[next_face..end].iter().collect(); +67 +68 if face_indices.len() != 3 { +69 return Err("we only handle triangulated faces".to_string()); +70 } +71 index_data.push([*face_indices[0], *face_indices[1], *face_indices[2]]); +72 next_face = end; +73 } +74 +75 if mesh.positions.len() % 3 != 0 { +76 return Err(format!("position array not % 3 : {}", mesh.positions.len())) +77 } +78 if mesh.texcoords.len() % 2 != 0 { +79 return Err(format!("position array not % 3 : {}", mesh.positions.len())) +80 } +81 if mesh.normals.is_empty() { +82 return Err(format!("It would be best if this had normals")) +83 } +84 if mesh.texcoords.is_empty() { +85 log::info!("\tMesh texture coordinates empty") +86 } +87 +88 for v in 0..mesh.positions.len() / 3 { +89 let texcoords = if mesh.texcoords.len() == 0 { +90 [0.0, 0.0] +91 } else { +92 [mesh.texcoords[2 * v], mesh.texcoords[2 * v + 1]] +93 }; +94 +95 vertex_data.push(Vertex::from( +96 [ +97 mesh.positions[3 * v], +98 mesh.positions[3 * v + 1], +99 mesh.positions[3 * v + 2], +100 ], +101 [ +102 mesh.normals[3 * v], +103 mesh.normals[3 * v + 1], +104 mesh.normals[3 * v + 2], +105 ], +106 texcoords, +107 )); +108 } +109 } +110 Ok(RawMesh { +111 vertices: vertex_data.to_vec(), +112 indices: index_data.to_vec(), +113 }) +114 } +115 +116 // pub fn create_quad_mesh() -> RawMesh { +117 // +118 // let mut index_data: Vec<[u32; 3]> = Vec::new(); +119 // let mut vertex_data = Vec::new(); +120 // +121 // vertex_data.push(Vertex::from( +122 // [ +123 // mesh.positions[3 * v], +124 // mesh.positions[3 * v + 1], +125 // mesh.positions[3 * v + 2], +126 // ], +127 // [ +128 // mesh.normals[3 * v], +129 // mesh.normals[3 * v + 1], +130 // mesh.normals[3 * v + 2], +131 // ], +132 // [mesh.texcoords[2 * v], mesh.texcoords[2 * v + 1]], +133 // )); +134 // +135 // RawMesh { +136 // vertices: vertex_data.to_vec(), +137 // indices: index_data.to_vec(), +138 // } +139 // } +140+ + \ No newline at end of file diff --git a/exportToHTML/imgui_support.rs.html b/exportToHTML/imgui_support.rs.html new file mode 100644 index 0000000..3304650 --- /dev/null +++ b/exportToHTML/imgui_support.rs.html @@ -0,0 +1,32 @@ + + +
1 use crate::imgui_supp::extended_winit_imgui_support::WinitPlatform; +2 +3 +4 pub struct ImguiContext { +5 pub context: imgui::Context, +6 } +7 unsafe impl Send for ImguiContext {} +8 +9 pub struct ImguiPlatform { +10 pub platform: WinitPlatform, +11 } +12 unsafe impl Send for ImguiPlatform {}+ + \ No newline at end of file diff --git a/exportToHTML/index.html b/exportToHTML/index.html new file mode 100644 index 0000000..741b6ad --- /dev/null +++ b/exportToHTML/index.html @@ -0,0 +1 @@ +
1 use bytemuck::__core::ops::Range; +2 use bytemuck::{Zeroable, Pod}; +3 use cgmath::Point3; +4 use std::sync::Arc; +5 use wgpu::TextureView; +6 use crate::components::{RangeCopy, Position}; +7 use crate::render::OPENGL_TO_WGPU_MATRIX; +8 +9 +10 #[repr(C)] +11 #[derive(Clone, Copy)] +12 pub struct LightRaw { +13 proj: [[f32; 4]; 4], +14 pos: [f32; 4], +15 color: [f32; 4], +16 } +17 +18 unsafe impl Pod for LightRaw {} +19 +20 unsafe impl Zeroable for LightRaw {} +21 +22 #[derive(Clone, Debug)] +23 pub struct DirectionalLight { +24 pub color: wgpu::Color, +25 pub fov: f32, +26 pub depth: RangeCopy<f32>, +27 pub target_view: Arc<TextureView>, +28 } +29 +30 impl DirectionalLight { +31 pub fn to_raw(&self, pos: &Position) -> LightRaw { +32 use cgmath::{Deg, EuclideanSpace, Matrix4, PerspectiveFov, Point3, Vector3}; +33 +34 let point3d = Point3::new(pos.x, pos.y, pos.z); +35 let point3d_2 = Point3::new(pos.x, pos.y - 1.0, pos.z); +36 let mx_view = Matrix4::look_at(point3d, point3d_2, Vector3::unit_z()); +37 +38 let projection = PerspectiveFov { +39 fovy: Deg(self.fov).into(), +40 aspect: 1.0, +41 near: self.depth.start, +42 far: self.depth.end, +43 }; +44 let mx_correction = OPENGL_TO_WGPU_MATRIX; +45 let mx_view_proj = +46 mx_correction * cgmath::Matrix4::from(projection.to_perspective()) * mx_view; +47 LightRaw { +48 proj: *mx_view_proj.as_ref(), +49 pos: [pos.x, pos.y, pos.z, 1.0], +50 color: [ +51 self.color.r as f32, +52 self.color.g as f32, +53 self.color.b as f32, +54 1.0, +55 ], +56 } +57 } +58 }+ + \ No newline at end of file diff --git a/exportToHTML/main.rs.html b/exportToHTML/main.rs.html new file mode 100644 index 0000000..bc83a63 --- /dev/null +++ b/exportToHTML/main.rs.html @@ -0,0 +1,409 @@ + + +
1 extern crate env_logger; +2 extern crate imgui; +3 extern crate imgui_wgpu; +4 #[macro_use] +5 extern crate lazy_static; +6 #[macro_use] +7 extern crate serde_derive; +8 extern crate tobj; +9 extern crate toml; +10 extern crate winit_24; +11 +12 use std::collections::HashMap; +13 use std::f32::consts::PI; +14 use std::fs; +15 use std::sync::{Arc, Mutex}; +16 #[cfg(not(target_arch = "wasm32"))] +17 use std::time::{Duration, Instant}; +18 +19 use cgmath::{ +20 Decomposed, Deg, Euler, InnerSpace, Point3, Quaternion, Rad, Rotation3, SquareMatrix, +21 }; +22 use futures::executor::block_on; +23 use futures::task::LocalSpawn; +24 use futures::FutureExt; +25 use gilrs::Event as GilEvent; +26 use gilrs::{Gamepad, Gilrs}; +27 use imgui::FontSource; +28 use imgui::__core::convert::TryInto; +29 use imgui::*; +30 use imgui_wgpu::{Renderer as ImguiRenderer, RendererConfig as ImguiRendererConfig}; +31 use legion::systems::{SyncResources, UnsafeResources}; +32 use legion::*; +33 use log::LevelFilter; +34 use rapier3d::counters::Timer; +35 use rapier3d::dynamics::{ +36 IntegrationParameters, JointSet, RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet, +37 }; +38 use rapier3d::geometry::{BroadPhase, ColliderBuilder, ColliderHandle, ColliderSet, NarrowPhase}; +39 use rapier3d::math; +40 use rapier3d::math::Point; +41 use rapier3d::na::{Isometry, Isometry3, Vector, Vector3}; +42 use rapier3d::pipeline::PhysicsPipeline; +43 use wgpu::{BindGroup, Buffer, TextureView}; +44 use wgpu_subscriber; +45 use winit_24::event::DeviceEvent::MouseMotion; +46 use winit_24::event::{ElementState, VirtualKeyCode}; +47 use winit_24::event_loop::EventLoopProxy; +48 use winit_24::platform::unix::x11::ffi::Time; +49 use winit_24::window::Window; +50 use winit_24::{ +51 event::{self, WindowEvent}, +52 event_loop::{ControlFlow, EventLoop}, +53 }; +54 +55 use crate::camera::{Camera, CameraController}; +56 use crate::components::{Collider, ImguiWindow, LoopState, Physics, Position}; +57 use crate::geometry::{load_obj, RawMesh}; +58 use crate::imgui_supp::extended_winit_imgui_support; +59 use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; +60 use crate::owned_event::{OwnedEvent, OwnedEventExtension}; +61 use crate::physics::state::PhysicsState; +62 use crate::render::system::ImguiPerformanceProfilerLine; +63 use crate::runtime::state::RuntimeState; +64 use winit_24::dpi::PhysicalSize; +65 +66 mod camera; +67 mod components; +68 mod geometry; +69 mod imgui_supp; +70 mod light; +71 mod owned_event; +72 mod physics; +73 mod render; +74 mod runtime; +75 +76 /* +77 +78 Collision detection +79 https://nphysics.org/rigid_body_simulations_with_contacts/ +80 +81 Obj file format +82 http://paulbourke.net/dataformats/obj/ +83 +84 tobj obj loader +85 https://docs.rs/tobj/2.0.3/tobj/index.html +86 +87 mesh generator lib, might be useful +88 https://docs.rs/genmesh/0.6.2/genmesh/ +89 +90 legion ECS +91 https://github.com/amethyst/legion +92 +93 +94 ECS +95 animation +96 config / save loading (sorta!) +97 render 3d (good!) +98 input/io (yep!) +99 collision / physics (yep!) +100 entities & behaviours (got the entities!) +101 scripting! +102 +103 +104 Todo: +105 Load scene imgui interface w/ toml files +106 FPS graph port from voxel raycaster +107 better imgui interface with components & systems +108 Figure out eventing, GameInput, passing all events, etc. +109 + texturing +110 +111 I need to figure out the way that I want to do 2d graphics in a 3d engine... +112 I suppose I will need sprites. And those are just 2 polygons which are textured +113 +114 +115 +116 */ +117 +118 //log::info!(""); +119 +120 // ImGUI works on more or less an unsafe global state. which is MegaLame +121 static mut CURRENT_UI: Option<imgui::Ui<'static>> = None; +122 pub unsafe fn current_ui<'a>() -> Option<&'a imgui::Ui<'a>> { +123 CURRENT_UI.as_ref() +124 } +125 +126 +127 +128 fn main() { +129 let logger = env_logger::builder() +130 .filter(Some("minimal_viable_game_engine"), LevelFilter::Info) +131 .init(); +132 +133 let mut world = World::default(); +134 +135 let mut imgui_prepare_schedule = Schedule::builder() +136 .add_system(render::system::imgui_prepare_system()) +137 .build(); +138 +139 let mut load_schedule = Schedule::builder() +140 .add_system(runtime::system::runtime_load_system()) +141 .add_system(runtime::system::runtime_spawn_system()) +142 .flush() +143 .build(); +144 +145 let mut render_schedule = Schedule::builder() +146 .add_system(render::system::render_imgui_system()) +147 .add_system(render::system::render_test_system()) +148 .add_system(render::system::render_performance_flag_system()) +149 .build(); +150 +151 let mut update_schedule = Schedule::builder() +152 .add_system(physics::system::update_camera_system()) +153 .add_system(physics::system::run_physics_system()) +154 .add_system(physics::system::update_models_system()) +155 // next system here, gamelogic update system? +156 .build(); +157 +158 let mut event_schedule = Schedule::builder() +159 .add_system(owned_event::event_dispatch_system()) +160 .build(); +161 +162 let event_loop = EventLoop::<OwnedEventExtension>::with_user_event(); +163 let mut builder = winit_24::window::WindowBuilder::new(); +164 builder = builder.with_title("MVGE"); +165 builder = builder.with_inner_size(PhysicalSize::new(1200,900)); +166 +167 let window = builder.build(&event_loop).unwrap(); +168 +169 let mut resources = Resources::default(); +170 +171 +172 +173 // Load up all the resources +174 { +175 let mut imgui_context = imgui::Context::create(); +176 let mut platform = extended_winit_imgui_support::WinitPlatform::init(&mut imgui_context); +177 platform.attach_window( +178 imgui_context.io_mut(), +179 &window, +180 extended_winit_imgui_support::HiDpiMode::Default, +181 ); +182 +183 // imgui_supp rendering context +184 let mut imgui_context = ImguiContext { +185 context: imgui_context, +186 }; +187 let mut imgui_platform = ImguiPlatform { platform: platform }; +188 let font_size = 20.0 as f32; +189 imgui_context.context.io_mut().font_global_scale = 1.0 as f32; +190 imgui_context +191 .context +192 .fonts() +193 .add_font(&[FontSource::DefaultFontData { +194 config: Some(imgui::FontConfig { +195 oversample_h: 1, +196 pixel_snap_h: true, +197 size_pixels: font_size, +198 ..Default::default() +199 }), +200 }]); +201 imgui_context.context.set_ini_filename(None); +202 +203 // The renderer +204 let mut renderer = render::state::RenderState::init(&window, &mut imgui_context); +205 +206 resources.insert(renderer); +207 resources.insert(Arc::new(Mutex::new(imgui_context))); +208 resources.insert(Arc::new(Mutex::new(imgui_platform))); +209 resources.insert(window); +210 +211 // Physics +212 let (physics_state, physics_pipeline) = +213 PhysicsState::build(rapier3d::math::Vector::new(0.0, -9.81, 0.0)); +214 resources.insert(physics_state); +215 resources.insert(physics_pipeline); +216 +217 // Loop data +218 resources.insert(LoopState { +219 delta_time: Default::default(), +220 start_time: Instant::now(), +221 step_size: 0.01666, // 60hz +222 }); +223 +224 // And our event stack +225 resources.insert(Vec::<OwnedEvent<OwnedEventExtension>>::new()); +226 +227 // Our init and runtime data +228 resources.insert(RuntimeState::new()) +229 }; +230 +231 setup_gamepad(&event_loop); +232 +233 let mut elapsed_time: f32 = { +234 // deltatime since last frame +235 let loop_state = resources.get::<LoopState>().unwrap(); +236 loop_state.start_time.elapsed() +237 } +238 .as_secs_f32(); +239 +240 let mut delta_time: f32 = 0.0; +241 let mut accumulator_time: f32 = 0.0; +242 let mut current_time: f32 = elapsed_time; +243 +244 event_loop.run(move |event, _, control_flow| { +245 *control_flow = ControlFlow::Poll; +246 match event { +247 event::Event::NewEvents(cause) => { +248 if cause == winit_24::event::StartCause::Init { +249 load_schedule.execute(&mut world, &mut resources); +250 } +251 } +252 +253 // This is the big boy section of the event loop +254 // We : dispatch events and clear the queue, query the loops +255 // time data and prep the dt data. Loop the dt locked +256 // conditionally, and run the fps locked renderer +257 event::Event::MainEventsCleared => { +258 event_schedule.execute(&mut world, &mut resources); +259 resources +260 .get_mut::<Vec<OwnedEvent<OwnedEventExtension>>>() +261 .unwrap() +262 .clear(); +263 +264 imgui_prepare_schedule.execute(&mut world, &mut resources); +265 +266 let (step_size, elapsed_time) = { +267 let mut loop_state = resources.get_mut::<LoopState>().unwrap(); +268 ( +269 loop_state.step_size, +270 loop_state.start_time.elapsed().as_secs_f32(), +271 ) +272 }; +273 delta_time = elapsed_time - current_time; +274 +275 { +276 let mut loop_state = resources.get_mut::<LoopState>().unwrap(); +277 loop_state.delta_time = Duration::from_secs_f32(delta_time); +278 } +279 current_time = elapsed_time; +280 if delta_time > 0.02 { +281 delta_time = 0.02; +282 } +283 accumulator_time += delta_time; +284 +285 while accumulator_time - step_size >= step_size { +286 accumulator_time -= step_size; +287 +288 // ==== DELTA TIME LOCKED ==== +289 update_schedule.execute(&mut world, &mut resources); +290 } +291 // ==== FPS LOCKED ==== +292 render_schedule.execute(&mut world, &mut resources); +293 } +294 // Resizing will queue a request_redraw +295 event::Event::WindowEvent { +296 event: WindowEvent::Resized(size), +297 .. +298 } => { +299 let width = size.width; +300 let height = size.height; +301 +302 resources +303 .get_mut::<render::state::RenderState>() +304 .unwrap() +305 .resize(width, height); +306 } +307 event::Event::DeviceEvent { +308 event: winit_24::event::DeviceEvent::Key(keyboard_input), +309 .. +310 } => { +311 if keyboard_input.virtual_keycode.is_some() { +312 match keyboard_input.virtual_keycode.unwrap() { +313 VirtualKeyCode::Escape => { +314 if keyboard_input.state == ElementState::Pressed { +315 *control_flow = ControlFlow::Exit; +316 } else { +317 //d +318 } +319 } +320 _ => (), +321 } +322 } +323 } +324 event::Event::WindowEvent { +325 event: WindowEvent::CloseRequested, +326 .. +327 } => *control_flow = ControlFlow::Exit, +328 event::Event::RedrawRequested(_) => { +329 // Call the render system +330 // imgui_prepare_schedule.execute(&mut world, &mut resources); +331 // render_schedule.execute(&mut world, &mut resources); +332 } +333 _ => {} +334 } +335 +336 resources +337 .get_mut::<Vec<OwnedEvent<OwnedEventExtension>>>() +338 .unwrap() +339 .push(event.into()); +340 }); +341 } +342 +343 pub fn setup_gamepad(event_loop: &EventLoop<OwnedEventExtension>) { +344 let event_loop_proxy = event_loop.create_proxy(); +345 +346 std::thread::spawn(move || { +347 let mut gilrs = Gilrs::new().unwrap(); +348 // Iterate over all connected gamepads +349 let mut gamepad: Option<Gamepad> = None; +350 for (_id, gamepad_) in gilrs.gamepads() { +351 if gamepad_.name() == "PS4" { +352 gamepad = Some(gamepad_); +353 } +354 // println!( +355 // "{} is {:?} {:?}", +356 // gamepad_.name(), +357 // gamepad_.power_info(), +358 // gamepad_.id() +359 // ); +360 } +361 let mut active_gamepad = None; +362 +363 loop { +364 while let Some(GilEvent { id, event, time }) = gilrs.next_event() { +365 //println!("{:?} New event from {}: {:?}", time, id, event); +366 active_gamepad = Some(id); +367 event_loop_proxy +368 .send_event(OwnedEventExtension::GamepadEvent { +369 gil_event: GilEvent { id, event, time }, +370 }) +371 .ok(); +372 } +373 +374 // // You can also use cached gamepad state +375 // if let Some(gamepad) = active_gamepad.map(|id| gilrs.gamepad(id)) { +376 // if gamepad.is_pressed(Button::South) { +377 // println!("Button South is pressed (XBox - A, PS - X)"); +378 // } +379 // } +380 +381 std::thread::sleep(std::time::Duration::from_millis(50)); +382 } +383 }); +384 } +385+ + \ No newline at end of file diff --git a/exportToHTML/mod.rs.html b/exportToHTML/mod.rs.html new file mode 100644 index 0000000..f2bfced --- /dev/null +++ b/exportToHTML/mod.rs.html @@ -0,0 +1,22 @@ + + +
1 pub mod extended_winit_imgui_support; +2 pub mod imgui_support;+ + \ No newline at end of file diff --git a/exportToHTML/owned_event.rs.html b/exportToHTML/owned_event.rs.html new file mode 100644 index 0000000..f1f8ed5 --- /dev/null +++ b/exportToHTML/owned_event.rs.html @@ -0,0 +1,330 @@ + + +
1 use std::path::PathBuf; +2 +3 use gilrs::Event as GilEvent; +4 use legion::world::SubWorld; +5 use legion::*; +6 use winit_24::dpi::{PhysicalPosition, PhysicalSize, LogicalPosition}; +7 use winit_24::event::DeviceEvent::MouseMotion; +8 use winit_24::event::{AxisId, DeviceEvent, DeviceId, ElementState, Event, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, StartCause, Touch, TouchPhase, WindowEvent, VirtualKeyCode}; +9 use winit_24::window::{Theme, WindowId, Window}; +10 +11 use crate::camera::{Camera, CameraController}; +12 use crate::owned_event::OwnedWindowEvent::MouseWheel; +13 use std::sync::{Mutex, Arc}; +14 use std::cmp::Ordering; +15 use imgui::Io; +16 use crate::imgui_supp::imgui_support::{ImguiContext, ImguiPlatform}; +17 +18 #[derive(Clone)] +19 pub enum OwnedUIEvent<T> { +20 UIEvent(T), +21 } +22 +23 #[derive(Clone)] +24 pub enum OwnedEventExtension { +25 /// Custom events here +26 MouseHeldEvent {}, +27 KeyHeldEvent {}, +28 GamepadEvent { +29 gil_event: GilEvent, +30 }, +31 } +32 +33 #[derive(Clone, Debug)] +34 pub enum OwnedEvent<T> { +35 /// Custom events here +36 MouseHeldEvent {}, +37 KeyHeldEvent {}, +38 GamepadEvent { +39 gil_event: GilEvent, +40 }, +41 +42 /// Winit events here +43 NewEvents(StartCause), +44 WindowEvent { +45 window_id: WindowId, +46 event: OwnedWindowEvent, +47 }, +48 DeviceEvent { +49 device_id: DeviceId, +50 event: DeviceEvent, +51 }, +52 UserEvent(T), +53 Suspended, +54 Resumed, +55 MainEventsCleared, +56 RedrawRequested(WindowId), +57 RedrawEventsCleared, +58 LoopDestroyed, +59 } +60 +61 impl<T> From<Event<'_, T>> for OwnedEvent<T> { +62 fn from(event: Event<T>) -> Self { +63 match event { +64 Event::NewEvents(cause) => OwnedEvent::NewEvents(cause), +65 Event::WindowEvent { +66 window_id: window_id, +67 event: event, +68 } => OwnedEvent::WindowEvent { +69 window_id: window_id, +70 event: match event { +71 WindowEvent::AxisMotion { +72 device_id, +73 axis, +74 value, +75 } => OwnedWindowEvent::AxisMotion { +76 device_id, +77 axis, +78 value, +79 }, +80 WindowEvent::Resized(physical_size) => OwnedWindowEvent::Resized(physical_size), +81 WindowEvent::Moved(physical_position) => { +82 OwnedWindowEvent::Moved(physical_position) +83 } +84 WindowEvent::CloseRequested => OwnedWindowEvent::CloseRequested, +85 WindowEvent::Destroyed => OwnedWindowEvent::Destroyed, +86 WindowEvent::DroppedFile(path_buf) => OwnedWindowEvent::DroppedFile(path_buf), +87 WindowEvent::HoveredFile(path_buf) => OwnedWindowEvent::HoveredFile(path_buf), +88 WindowEvent::HoveredFileCancelled => OwnedWindowEvent::HoveredFileCancelled, +89 WindowEvent::ReceivedCharacter(char) => { +90 OwnedWindowEvent::ReceivedCharacter(char) +91 } +92 WindowEvent::Focused(bool) => OwnedWindowEvent::Focused(bool), +93 WindowEvent::KeyboardInput { +94 device_id: device_id, +95 input: input, +96 is_synthetic: is_synthetic, +97 } => OwnedWindowEvent::KeyboardInput { +98 device_id, +99 input, +100 is_synthetic, +101 }, +102 WindowEvent::ModifiersChanged(modifiers_state) => { +103 OwnedWindowEvent::ModifiersChanged(modifiers_state) +104 } +105 WindowEvent::CursorMoved { +106 device_id: device_id, +107 position: position, +108 modifiers: modifiers, +109 } => OwnedWindowEvent::CursorMoved { +110 device_id, +111 position, +112 modifiers, +113 }, +114 WindowEvent::CursorEntered { +115 device_id: device_id, +116 } => OwnedWindowEvent::CursorEntered { device_id }, +117 WindowEvent::CursorLeft { +118 device_id: device_id, +119 } => OwnedWindowEvent::CursorLeft { device_id }, +120 WindowEvent::MouseWheel { +121 device_id: device_id, +122 delta: delta, +123 phase: phase, +124 modifiers: modifiers, +125 } => OwnedWindowEvent::MouseWheel { +126 device_id, +127 delta, +128 phase, +129 modifiers, +130 }, +131 WindowEvent::MouseInput { +132 device_id: device_id, +133 state: state, +134 button: button, +135 modifiers: modifiers, +136 } => OwnedWindowEvent::MouseInput { +137 device_id, +138 state, +139 button, +140 modifiers, +141 }, +142 WindowEvent::TouchpadPressure { +143 device_id: device_id, +144 pressure: pressure, +145 stage: stage, +146 } => OwnedWindowEvent::TouchpadPressure { +147 device_id, +148 pressure, +149 stage, +150 }, +151 WindowEvent::Touch(touch) => OwnedWindowEvent::Touch(touch), +152 WindowEvent::ScaleFactorChanged { +153 scale_factor: scale_factor, +154 new_inner_size: new_inner_size, +155 } => OwnedWindowEvent::ScaleFactorChanged { +156 scale_factor, +157 new_inner_size: PhysicalSize { +158 width: new_inner_size.width, +159 height: new_inner_size.height, +160 }, +161 }, +162 WindowEvent::ThemeChanged(theme) => OwnedWindowEvent::ThemeChanged(theme), +163 }, +164 }, +165 Event::DeviceEvent { +166 device_id: device_id, +167 event: event, +168 } => OwnedEvent::DeviceEvent { device_id, event }, +169 Event::UserEvent(user_event) => OwnedEvent::UserEvent(user_event), +170 Event::Suspended => OwnedEvent::Suspended, +171 Event::Resumed => OwnedEvent::Resumed, +172 Event::MainEventsCleared => OwnedEvent::MainEventsCleared, +173 Event::RedrawRequested(window_id) => OwnedEvent::RedrawRequested(window_id), +174 Event::RedrawEventsCleared => OwnedEvent::RedrawEventsCleared, +175 Event::LoopDestroyed => OwnedEvent::LoopDestroyed, +176 } +177 } +178 } +179 +180 #[derive(Debug, PartialEq, Clone)] +181 pub enum OwnedWindowEvent { +182 Resized(PhysicalSize<u32>), +183 Moved(PhysicalPosition<i32>), +184 CloseRequested, +185 Destroyed, +186 DroppedFile(PathBuf), +187 HoveredFile(PathBuf), +188 HoveredFileCancelled, +189 ReceivedCharacter(char), +190 Focused(bool), +191 KeyboardInput { +192 device_id: DeviceId, +193 input: KeyboardInput, +194 is_synthetic: bool, +195 }, +196 ModifiersChanged(ModifiersState), +197 CursorMoved { +198 device_id: DeviceId, +199 position: PhysicalPosition<f64>, +200 #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] +201 modifiers: ModifiersState, +202 }, +203 CursorEntered { +204 device_id: DeviceId, +205 }, +206 CursorLeft { +207 device_id: DeviceId, +208 }, +209 MouseWheel { +210 device_id: DeviceId, +211 delta: MouseScrollDelta, +212 phase: TouchPhase, +213 #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] +214 modifiers: ModifiersState, +215 }, +216 MouseInput { +217 device_id: DeviceId, +218 state: ElementState, +219 button: MouseButton, +220 #[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"] +221 modifiers: ModifiersState, +222 }, +223 TouchpadPressure { +224 device_id: DeviceId, +225 pressure: f32, +226 stage: i64, +227 }, +228 AxisMotion { +229 device_id: DeviceId, +230 axis: AxisId, +231 value: f64, +232 }, +233 Touch(Touch), +234 ScaleFactorChanged { +235 scale_factor: f64, +236 new_inner_size: PhysicalSize<u32>, +237 }, +238 ThemeChanged(Theme), +239 } +240 +241 +242 /// Because I am a glutton for punishment I am going to just do a mono-event-dispatch-magoooo +243 #[system] +244 #[write_component(Camera)] +245 #[write_component(CameraController)] +246 pub fn event_dispatch( +247 world: &mut SubWorld, +248 #[resource] event_stack: &mut Vec<OwnedEvent<OwnedEventExtension>>, +249 #[resource] imgui_context: &mut Arc<Mutex<ImguiContext>>, +250 #[resource] imgui_platform: &mut Arc<Mutex<ImguiPlatform>>, +251 #[resource] winit_window: &mut Window, +252 ) { +253 use winit_24::event::Event::DeviceEvent; +254 +255 for event in event_stack { +256 +257 match event { +258 OwnedEvent::DeviceEvent { +259 event: winit_24::event::DeviceEvent::MouseMotion { delta }, +260 .. +261 } => { +262 let mut query = <(&mut CameraController)>::query(); +263 for (camera_controller) in query.iter_mut(world) { +264 camera_controller.process_mouse(delta.0, delta.1); +265 } +266 +267 }, +268 OwnedEvent::DeviceEvent { +269 event: winit_24::event::DeviceEvent::Key(keyboard_input), +270 .. +271 } => { +272 let mut query = <(&mut CameraController)>::query(); +273 for (camera_controller) in query.iter_mut(world) { +274 camera_controller.process_keyboard( +275 keyboard_input.virtual_keycode.unwrap(), +276 keyboard_input.state, +277 ); +278 } +279 +280 match keyboard_input.virtual_keycode.unwrap() { +281 VirtualKeyCode::R => { +282 if keyboard_input.state == ElementState::Pressed { +283 +284 +285 //winit_window.set_cursor_grab(true); +286 } +287 } +288 VirtualKeyCode::Escape => { +289 if keyboard_input.state == ElementState::Pressed { +290 //winit_window.set_cursor_grab(false); +291 } +292 } +293 _ => () +294 } +295 } +296 _ => {} +297 } +298 +299 let mut imgui_context = &mut imgui_context.lock().unwrap().context; +300 let mut imgui_platform = &mut imgui_platform.lock().unwrap().platform; +301 +302 imgui_platform.handle_event(imgui_context.io_mut(), &winit_window, &event); +303 } +304 } +305+ + \ No newline at end of file diff --git a/exportToHTML/state.rs.html b/exportToHTML/state.rs.html new file mode 100644 index 0000000..a34726b --- /dev/null +++ b/exportToHTML/state.rs.html @@ -0,0 +1,138 @@ + + +
1 use std::collections::HashMap; +2 use std::fs; +3 use std::path::PathBuf; +4 use std::time::Instant; +5 use serde_derive::Deserialize; +6 +7 use cgmath::{Euler, Quaternion, Deg}; +8 use legion::world::SubWorld; +9 use legion::IntoQuery; +10 use legion::*; +11 use nalgebra::Quaternion as naQuaternion; +12 use rapier3d::dynamics::{IntegrationParameters, JointSet, RigidBodySet}; +13 use rapier3d::geometry::{BroadPhase, ColliderSet, NarrowPhase}; +14 use rapier3d::pipeline::PhysicsPipeline; +15 use crate::camera::{Camera, CameraController}; +16 use crate::components::{Collider, LoopState, Mesh, Physics, Position}; +17 use crate::geometry::{load_obj, RawMesh}; +18 use std::io::Read; +19 +20 +21 +22 #[derive(Deserialize, Clone)] +23 pub struct TomlBallPhysicsBodyDescription { +24 pub radius: String +25 } +26 +27 #[derive(Deserialize, Clone)] +28 pub struct TomlCuboidPhysicsBodyDescription { +29 pub x: f32, +30 pub y: f32, +31 pub z: f32, +32 } +33 +34 #[derive(Deserialize, Clone)] +35 pub struct TomlPhysicsDescription { +36 pub body_status: String, +37 pub ball: Option<TomlBallPhysicsBodyDescription>, +38 pub cuboid: Option<TomlCuboidPhysicsBodyDescription>, +39 } +40 +41 #[derive(Deserialize, Clone)] +42 pub struct TomlRotationDescription { +43 pub x: f32, +44 pub y: f32, +45 pub z: f32, +46 } +47 +48 #[derive(Deserialize, Clone)] +49 pub struct TomlPositionDescription { +50 pub x: f32, +51 pub y: f32, +52 pub z: f32, +53 pub rot: Option<TomlRotationDescription>, +54 } +55 +56 #[derive(Deserialize, Clone)] +57 pub struct TomlEntityDescription { +58 pub name: String, +59 #[serde(rename = "type")] +60 pub type_name: String, +61 pub mesh: Option<String>, +62 pub position: Option<TomlPositionDescription>, +63 pub physics: Option<TomlPhysicsDescription>, +64 } +65 +66 #[derive(Deserialize, Clone)] +67 pub struct TomlEntityContainer { +68 pub entities: Vec<TomlEntityDescription>, +69 } +70 +71 pub struct RuntimeState { +72 config_db: TomlEntityContainer, +73 mesh_cache: HashMap<String, RawMesh>, +74 } +75 +76 impl RuntimeState { +77 pub fn new() -> RuntimeState { +78 // TODO: Hook this file to the gui +79 let mut file = fs::File::open("./conf/entity_spawns.toml").unwrap(); +80 let mut content = String::new(); +81 file.read_to_string(&mut content).unwrap(); +82 +83 // TODO: gracefully fail +84 let mut settings : TomlEntityContainer = toml::from_str(content.as_str()).unwrap(); +85 +86 RuntimeState { +87 config_db: settings, +88 mesh_cache: Default::default(), +89 } +90 } +91 +92 pub fn get_mesh(&mut self, mesh: &str) -> Option<&RawMesh> { +93 self.mesh_cache.get(mesh) +94 } +95 +96 pub fn get_entities(&mut self) -> Vec<TomlEntityDescription> { +97 self.config_db.entities.clone() +98 } +99 +100 pub fn preload_meshes(&mut self, resources_path: PathBuf) { +101 log::info!("Preloading meshes..."); +102 +103 let paths = fs::read_dir(resources_path).unwrap(); +104 for file in paths { +105 let file = file.unwrap(); +106 let filepath = file.path().clone(); +107 let filename = String::from(file.file_name().to_str().unwrap()); +108 +109 if filename.ends_with(".obj") { +110 let mesh = load_obj(filepath.to_str().unwrap()).unwrap(); +111 self.mesh_cache.insert(filename, mesh); +112 } +113 } +114 } +115 } +116+ + \ No newline at end of file diff --git a/exportToHTML/system.rs.html b/exportToHTML/system.rs.html new file mode 100644 index 0000000..3a08027 --- /dev/null +++ b/exportToHTML/system.rs.html @@ -0,0 +1,356 @@ + + +
1 use std::f32::consts::PI; +2 use std::path::PathBuf; +3 use std::time::Instant; +4 +5 use cgmath::{Deg, Euler, Point3, Quaternion, Rad}; +6 use imgui::*; +7 use imgui::{Condition, FontSource, Ui}; +8 use legion::systems::CommandBuffer; +9 use legion::world::SubWorld; +10 use legion::IntoQuery; +11 use legion::*; +12 use nalgebra::Quaternion as naQuaternion; +13 use rapier3d::dynamics::{ +14 IntegrationParameters, JointSet, MassProperties, RigidBodyBuilder, RigidBodySet, +15 }; +16 use rapier3d::geometry::{BroadPhase, ColliderBuilder, ColliderSet, NarrowPhase}; +17 use rapier3d::na::{Isometry3, Vector, Vector3}; +18 use rapier3d::pipeline::{ChannelEventCollector, PhysicsPipeline}; +19 +20 use crate::camera::{Camera, CameraController}; +21 use crate::components::{Collider, ImguiWindow, LoopState, Mesh, Physics, Position}; +22 use crate::geometry; +23 use crate::physics::state::PhysicsState; +24 use crate::render::state::RenderState; +25 use crate::render::system::{ImguiGenericOutputLine, ImguiPerformanceProfilerLine}; +26 use crate::runtime::state::RuntimeState; +27 use crate::geometry::RawMesh; +28 +29 pub fn quad_color(color: [f32; 4]) -> [[f32; 4]; 4] { +30 [color, color, color, color] +31 } +32 +33 #[system] +34 #[write_component(Mesh)] +35 pub fn runtime_load( +36 cmd: &mut CommandBuffer, +37 world: &mut SubWorld, +38 #[resource] runtime_state: &mut RuntimeState, +39 ) { +40 runtime_state.preload_meshes(PathBuf::from("./resources")); +41 +42 let entity: Entity = cmd.push((ImguiWindow { +43 // a window that does everything for the performance profiler +44 window: || { +45 imgui::Window::new(im_str!("Performance Profiler")) +46 .size([400.0, 200.0], Condition::FirstUseEver) +47 .position([10.0, 10.0], Condition::FirstUseEver) +48 }, +49 func: |ui: &Ui, a: Vec<&ImguiPerformanceProfilerLine>| { +50 // ui.text(im_str!("Performance Graph")); +51 +52 let draw_list = ui.get_window_draw_list(); +53 let top_left = ui.cursor_screen_pos(); +54 let region_size = ui.content_region_avail(); +55 +56 let region_size = [region_size[0] * 0.80, region_size[1]]; +57 +58 // Fill rect +59 let qcolor = quad_color([0.5, 0.5, 1.0, 0.1]); +60 draw_list.add_rect_filled_multicolor( +61 top_left, +62 [top_left[0] + (region_size[0]), top_left[1] + region_size[1]], +63 qcolor[0], +64 qcolor[1], +65 qcolor[2], +66 qcolor[3], +67 ); +68 +69 for profiler_line in a { +70 let x_scale = (region_size[0]) / 400.0; +71 let y_scale = region_size[1] / profiler_line.scale_max; +72 profiler_line +73 .iter_data_from_head() +74 .fold((0, 0.0f32), |accum, &fps_val| { +75 let x1 = accum.0 as f32 * x_scale + top_left[0]; +76 let y1 = top_left[1] + region_size[1] - accum.1 * y_scale; +77 let x2 = (accum.0 as f32 + 1.0) * x_scale + top_left[0]; +78 let y2 = top_left[1] + region_size[1] - fps_val * y_scale; +79 let p1 = [x1, y1]; +80 let p2 = [x2, y2]; +81 draw_list +82 .add_line(p1, p2, [1.0, 1.0, 0.0, 0.8]) +83 .thickness(1.0) +84 .build(); +85 (accum.0 + 1, fps_val) +86 }); +87 +88 let text_x = (region_size[0] + top_left[0]); +89 let text_y = top_left[1] + region_size[1] +90 - profiler_line.current_average_label().0 * y_scale; +91 draw_list.add_text( +92 [text_x, text_y], +93 [1.0, 1.0, 0.0, 1.0], +94 format!( +95 "{} {:.0}", +96 profiler_line.current_average_label().1, +97 1.0 / profiler_line.current_average_label().0 +98 ), +99 ); +100 } +101 }, +102 },)); +103 let entity: Entity = cmd.push((ImguiPerformanceProfilerLine::new("RenderFPS".to_string()),)); +104 +105 let entity: Entity = cmd.push((ImguiWindow { +106 // a window that does everything for the performance profiler +107 window: || { +108 imgui::Window::new(im_str!("Generic Output")) +109 .size([400.0, 500.0], Condition::FirstUseEver) +110 .position([50.0, 250.0], Condition::FirstUseEver) +111 }, +112 func: |ui: &Ui, a: Vec<&ImguiGenericOutputLine>| { +113 for label in a { +114 ui.text(im_str!("{}", label.label)); +115 } +116 }, +117 },)); +118 } +119 +120 #[system] +121 #[write_component(Mesh)] +122 pub fn runtime_spawn( +123 cmd: &mut CommandBuffer, +124 world: &mut SubWorld, +125 #[resource] runtime_state: &mut RuntimeState, +126 #[resource] renderer: &mut RenderState, +127 ) { +128 for entity in &runtime_state.get_entities() { +129 match entity.type_name.as_ref() { +130 "Sprite" => { +131 +132 +133 +134 let mesh_name = entity.mesh.clone().unwrap(); +135 let raw_mesh = match runtime_state.get_mesh(mesh_name.as_str()) { +136 None => { +137 log::warn!("Skipping entity with invalid mesh file {:?} ", mesh_name); +138 continue; +139 } +140 Some(mesh) => mesh, +141 }; +142 +143 let position = Position::from(entity.position.clone()); +144 +145 let mut static_body = RigidBodyBuilder::new_static() +146 .position(Isometry3::new( +147 Vector3::new(position.x, position.y, position.z), +148 Vector::y(), +149 )) +150 .build(); +151 +152 let mesh_collider = ColliderBuilder::trimesh( +153 raw_mesh.vertices.iter().map(|v| v.position()).collect(), +154 raw_mesh.indices.clone(), +155 ) +156 .build(); +157 +158 let gpu_mesh_buffer = renderer +159 .upload_mesh_to_buffer( +160 raw_mesh, +161 Some(wgpu::Color { +162 r: 1.0, +163 g: 0.7, +164 b: 0.3, +165 a: 1.0, +166 }), +167 ) +168 .unwrap(); +169 +170 let entity: Entity = cmd.push(( +171 position, +172 gpu_mesh_buffer, +173 Physics { +174 rigid_body: static_body, +175 rigid_body_handle: None, +176 }, +177 Collider { +178 collider: mesh_collider, +179 collider_handle: None, +180 }, +181 )); +182 } +183 "PhysicsEntity" => { +184 let mesh_name = entity.mesh.as_ref().unwrap(); +185 let raw_mesh = match runtime_state.get_mesh(mesh_name.as_str()) { +186 None => { +187 log::warn!("Skipping entity with invalid mesh file {:?} ", mesh_name); +188 continue; +189 } +190 Some(mesh) => mesh, +191 }; +192 +193 let collider = ColliderBuilder::trimesh( +194 raw_mesh.vertices.iter().map(|v| v.position()).collect(), +195 raw_mesh.indices.clone(), +196 ) +197 .build(); +198 +199 let collider = ColliderBuilder::capsule_y(2.0, 1.0).build(); +200 +201 let gpu_mesh_buffer = renderer +202 .upload_mesh_to_buffer( +203 raw_mesh, +204 Some(wgpu::Color { +205 r: 1.0, +206 g: 0.7, +207 b: 0.3, +208 a: 1.0, +209 }), +210 ) +211 .unwrap(); +212 +213 let position = Position::from(entity.position.clone()); +214 +215 let mut dynamic_body = RigidBodyBuilder::new_dynamic() +216 .can_sleep(false) +217 .mass(100.0) +218 .translation(position.x, position.y, position.z) +219 .build(); +220 +221 let entity: Entity = cmd.push(( +222 position, +223 gpu_mesh_buffer, +224 Physics { +225 rigid_body: dynamic_body, +226 rigid_body_handle: None, +227 }, +228 Collider { +229 collider: collider, +230 collider_handle: None, +231 }, +232 ImguiGenericOutputLine::new("wahoo! from a physics entity".to_string()), +233 )); +234 } +235 "StaticMesh" => { +236 let mesh_name = entity.mesh.clone().unwrap(); +237 let raw_mesh = match runtime_state.get_mesh(mesh_name.as_str()) { +238 None => { +239 log::warn!("Skipping entity with invalid mesh file {:?} ", mesh_name); +240 continue; +241 } +242 Some(mesh) => mesh, +243 }; +244 +245 let position = Position::from(entity.position.clone()); +246 +247 let mut static_body = RigidBodyBuilder::new_static() +248 .position(Isometry3::new( +249 Vector3::new(position.x, position.y, position.z), +250 Vector::y(), +251 )) +252 .build(); +253 +254 let mesh_collider = ColliderBuilder::trimesh( +255 raw_mesh.vertices.iter().map(|v| v.position()).collect(), +256 raw_mesh.indices.clone(), +257 ) +258 .build(); +259 +260 let gpu_mesh_buffer = renderer +261 .upload_mesh_to_buffer( +262 raw_mesh, +263 Some(wgpu::Color { +264 r: 1.0, +265 g: 0.7, +266 b: 0.3, +267 a: 1.0, +268 }), +269 ) +270 .unwrap(); +271 +272 let entity: Entity = cmd.push(( +273 position, +274 gpu_mesh_buffer, +275 Physics { +276 rigid_body: static_body, +277 rigid_body_handle: None, +278 }, +279 Collider { +280 collider: mesh_collider, +281 collider_handle: None, +282 }, +283 )); +284 } +285 "Camera" => { +286 let position = Position::from(entity.position.clone()); +287 let entity: Entity = cmd.push(( +288 Camera { +289 position: cgmath::Point3 { +290 x: position.x, +291 y: position.y, +292 z: position.z, +293 }, +294 yaw: Rad(PI / 2.0), +295 pitch: Rad(PI / 2.0 + 25.0), +296 }, +297 CameraController::new(5.0, 1.0), +298 ImguiGenericOutputLine::new("wahoo! from a camera".to_string()), +299 )); +300 } +301 "Light" => { +302 let mesh_name = entity.mesh.clone().unwrap(); +303 let raw_mesh = match runtime_state.get_mesh(mesh_name.as_str()) { +304 None => { +305 log::warn!("Skipping entity with invalid mesh file {:?} ", mesh_name); +306 continue; +307 } +308 Some(mesh) => mesh, +309 }; +310 +311 let position = Position::from(entity.position.clone()); +312 +313 let gpu_mesh_buffer = renderer +314 .upload_mesh_to_buffer( +315 raw_mesh, +316 Some(wgpu::Color { +317 r: 1.0, +318 g: 0.7, +319 b: 0.3, +320 a: 1.0, +321 }), +322 ) +323 .unwrap(); +324 +325 let light_entity: Entity = +326 cmd.push((position, gpu_mesh_buffer, renderer.create_light())); +327 } +328 +329 _ => {} +330 } +331 } +332 } +333+ + \ No newline at end of file diff --git a/src/components.rs b/src/components.rs index 233982c..97ed73d 100644 --- a/src/components.rs +++ b/src/components.rs @@ -10,8 +10,9 @@ use wgpu::{BindGroup, Buffer, TextureView}; use crate::runtime::state::{TomlPositionDescription, TomlRotationDescription}; use imgui::Ui; -// a component is any type that is 'static, sized, send and sync - +/// a component is any type that is 'static, sized, send and sync +/// ImguiWindow contains a single handle and lifetime to an Imgui window, along with +/// a function which takes a UI, as well as a vector of a user defined type T pub struct ImguiWindow<'a, T> { pub window: fn() -> imgui::Window<'a>, pub func: fn(&Ui, Vec<&T>), diff --git a/src/geometry.rs b/src/geometry.rs index 8af1efa..29cb71a 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -35,6 +35,8 @@ pub struct RawMesh { } + + /// We use meshes in a few different places. To keep things simple, we return /// the most basic, direct-to-memory version. If something fancy needs to be done /// with it, the fancy stays there diff --git a/src/main.rs b/src/main.rs index 1cbb64a..2c46a6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -110,13 +110,28 @@ Todo: I need to figure out the way that I want to do 2d graphics in a 3d engine... I suppose I will need sprites. And those are just 2 polygons which are textured + */ - */ + +/** + +Notes: + +(Im)GUI, +* I have to hold onto an ImGUI window and it's lifetime +* I have to execute a bunch of function calls to build + the immediate mode UI each and every frame + +It looks like my solution was to have an entity describing +the window + + +*/ //log::info!(""); -// ImGUI works on more or less an unsafe global state. which is MegaLame +/// ImGUI works on more or less an unsafe global state. which is MegaLame static mut CURRENT_UI: Option