mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-09 00:09:55 +00:00
Sync Bevy canvas size with browser viewport size
This commit is contained in:
Generated
+1
@@ -2867,6 +2867,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"console_error_panic_hook",
|
||||
"parking_lot",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
||||
Generated
+9
-2
@@ -9,6 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -18,6 +19,7 @@
|
||||
"@nx/workspace": "16.9.1",
|
||||
"@nxrs/cargo": "^0.3.3",
|
||||
"@swc/core": "~1.3.85",
|
||||
"@types/lodash": "^4.14.199",
|
||||
"@types/node": "18.7.1",
|
||||
"@vitest/ui": "~0.32.0",
|
||||
"jsdom": "~22.1.0",
|
||||
@@ -3187,6 +3189,12 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.199",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz",
|
||||
"integrity": "sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.1.tgz",
|
||||
@@ -5608,8 +5616,7 @@
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"@nx/workspace": "16.9.1",
|
||||
"@nxrs/cargo": "^0.3.3",
|
||||
"@swc/core": "~1.3.85",
|
||||
"@types/lodash": "^4.14.199",
|
||||
"@types/node": "18.7.1",
|
||||
"@vitest/ui": "~0.32.0",
|
||||
"jsdom": "~22.1.0",
|
||||
@@ -26,6 +27,7 @@
|
||||
"wasm-pack": "^0.12.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21",
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as studio from "@storyteller/studio";
|
||||
import { ViewportSize } from "@storyteller/studio";
|
||||
import { throttle } from "lodash";
|
||||
|
||||
import "./app.element.scss";
|
||||
|
||||
@@ -7,11 +8,29 @@ export class AppElement extends HTMLElement {
|
||||
static observedAttributes = [];
|
||||
|
||||
connectedCallback(): void {
|
||||
// TODO: This siezes up the whole browser for several seconds, presumably
|
||||
// while the WASM binary is loading. Is there any way to do this
|
||||
// asynchronously?
|
||||
const { width, height } = document.body.getBoundingClientRect();
|
||||
studio.init(new ViewportSize(width, height));
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
try {
|
||||
// TODO: This siezes up the whole browser for several seconds, presumably
|
||||
// while the WASM binary is loading. Is there any way to do this
|
||||
// asynchronously?
|
||||
studio.init(new ViewportSize(width, height));
|
||||
} catch (err) {
|
||||
if (!(err as Error).message?.startsWith("Using exceptions for control flow"))
|
||||
throw err;
|
||||
}
|
||||
|
||||
window.addEventListener("resize", this.onResize);
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
window.removeEventListener("resize", this.onResize);
|
||||
}
|
||||
|
||||
onResize = throttle(() => {
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
studio.resize(new ViewportSize(width, height));
|
||||
}, 16.666);
|
||||
}
|
||||
customElements.define("app-root", AppElement);
|
||||
|
||||
@@ -15,6 +15,7 @@ path = "src/main.rs"
|
||||
[dependencies]
|
||||
wasm-bindgen = { version = "0.2.84" }
|
||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
[features]
|
||||
wasm = ["dep:console_error_panic_hook"]
|
||||
|
||||
+17
-13
@@ -17,21 +17,25 @@ pub fn init(viewport_size: ViewportSize) {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
App::new()
|
||||
.add_plugins((
|
||||
DefaultPlugins.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
resolution: viewport_size.into(),
|
||||
..default()
|
||||
}),
|
||||
let mut app = App::new();
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
app.add_plugins(viewport::wasm::ViewportPlugin);
|
||||
|
||||
app.add_plugins((
|
||||
DefaultPlugins.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
resolution: viewport_size.into(),
|
||||
..default()
|
||||
}),
|
||||
OrbitCamPlugin,
|
||||
TestScenePlugin,
|
||||
UiLayerPlugin,
|
||||
))
|
||||
.add_systems(Update, draw_world_axes.after(orbit_cam::pan_orbit_camera))
|
||||
.run();
|
||||
..default()
|
||||
}),
|
||||
OrbitCamPlugin,
|
||||
TestScenePlugin,
|
||||
UiLayerPlugin,
|
||||
))
|
||||
.add_systems(Update, draw_world_axes.after(orbit_cam::pan_orbit_camera))
|
||||
.run();
|
||||
}
|
||||
|
||||
fn draw_world_axes(mut gizmos: Gizmos, q: Query<&OrbitCam>) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use core::fmt;
|
||||
|
||||
use bevy::window::WindowResolution;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ViewportSize {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
@@ -35,3 +38,66 @@ impl From<WindowResolution> for ViewportSize {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ViewportSize {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_fmt(format_args!("({:.2}, {:.2})", self.width, self.height))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub mod wasm {
|
||||
use std::{cell::RefCell, sync::OnceLock};
|
||||
|
||||
use bevy::prelude::*;
|
||||
use parking_lot::ReentrantMutex;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use super::ViewportSize;
|
||||
|
||||
static RESIZE_BUF: OnceLock<ReentrantMutex<RefCell<Option<ViewportSize>>>> = OnceLock::new();
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn resize(viewport_size: ViewportSize) {
|
||||
let buffer = RESIZE_BUF.get_or_init(|| ReentrantMutex::new(RefCell::new(None)));
|
||||
if let Some(lock) = buffer.try_lock() {
|
||||
*lock.borrow_mut() = Some(viewport_size);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewportPlugin;
|
||||
|
||||
impl Plugin for ViewportPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_event::<ViewportResizeEvent>()
|
||||
.add_systems(PreUpdate, dispatch_viewport_events)
|
||||
.add_systems(Update, sync_window_to_viewport);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Event, Clone, Copy)]
|
||||
struct ViewportResizeEvent(ViewportSize);
|
||||
|
||||
fn sync_window_to_viewport(
|
||||
mut events: EventReader<ViewportResizeEvent>,
|
||||
mut window: Query<&mut Window>,
|
||||
) {
|
||||
let mut resize = None;
|
||||
for event in events.into_iter() {
|
||||
resize = Some(event.0);
|
||||
}
|
||||
|
||||
if let Some(ViewportSize { width, height }) = resize {
|
||||
window.single_mut().resolution.set(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch_viewport_events(mut events: EventWriter<ViewportResizeEvent>) {
|
||||
let buffer = RESIZE_BUF.get_or_init(|| ReentrantMutex::new(RefCell::new(None)));
|
||||
if let Some(lock) = buffer.try_lock() {
|
||||
if let Some(resize) = lock.borrow_mut().take() {
|
||||
events.send(ViewportResizeEvent(resize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user