From 04ba5bad69625ef0712e833bb5ab8b505b02c95d Mon Sep 17 00:00:00 2001 From: Danny McGee Date: Wed, 28 Feb 2024 02:30:19 -0500 Subject: [PATCH] Exclude editor visuals from screen captures --- image-generator-demo/src/app/app.element.ts | 30 ++++------- studio/src/interaction/gizmos/common.rs | 2 +- studio/src/interaction/gizmos/mod.rs | 1 + studio/src/wasm/screenshot.rs | 60 +++++++++++++++++++-- studio/src/world_grid.rs | 2 +- 5 files changed, 67 insertions(+), 28 deletions(-) diff --git a/image-generator-demo/src/app/app.element.ts b/image-generator-demo/src/app/app.element.ts index 606c239..33f1b9a 100644 --- a/image-generator-demo/src/app/app.element.ts +++ b/image-generator-demo/src/app/app.element.ts @@ -22,7 +22,6 @@ import "./app.element.scss" @customElement("app-root") export class AppElement extends LitElement { @state() imageCaptureUrl?: string; - @state() realtimeCapture = true; @state() hierarchyWidth = 256; @state() resizing = false; @@ -52,12 +51,9 @@ export class AppElement extends LitElement { } @on("entity-changes") + @debounce(1000 / 24) onStudioChanges(): void { - if (this.realtimeCapture) { - this.requestScreenshot_realtime(); - } else { - this.requestScreenshot_delayed(); - } + studio.requestScreenshot(); } @on("viewport-resized") @@ -67,16 +63,6 @@ export class AppElement extends LitElement { studio.requestScreenshot(); } - @debounce(1000 / 24, { maxWait: 1000 / 5 }) - requestScreenshot_realtime() { - studio.requestScreenshot(); - } - - @debounce(1000 / 24) - requestScreenshot_delayed() { - studio.requestScreenshot(); - } - @on("screenshot-ready") onScreenshotReady({ detail: screenshot }: ScreenshotReadyEvent) { const prevUrl = this.imageCaptureUrl; @@ -101,11 +87,6 @@ export class AppElement extends LitElement { this.hierarchyWidth = Math.max(Math.min(updated, 512), 128); } - toggleRealtimeCapture(event: InputEvent): void { - const { checked } = event.target as HTMLInputElement; - this.realtimeCapture = checked; - } - refreshSeed(): void { this.seed = randomSeed(); } @@ -184,6 +165,11 @@ export class AppElement extends LitElement { + ${/* + FIXME: Real-time capture is not really feasible until we can come up + with a more elegant way to exclude the world grid, gizmos, etc. + from the captured image +
+ */ + nothing} ${this.loading ? html` diff --git a/studio/src/interaction/gizmos/common.rs b/studio/src/interaction/gizmos/common.rs index b507901..6c5e46f 100644 --- a/studio/src/interaction/gizmos/common.rs +++ b/studio/src/interaction/gizmos/common.rs @@ -6,7 +6,7 @@ use crate::interaction::TransformSpace; use super::material::GizmoMaterial; #[derive(Component, Reflect)] -pub(super) struct TransformGizmo { +pub struct TransformGizmo { pub(super) target: Entity, pub(super) transform_space: TransformSpace, } diff --git a/studio/src/interaction/gizmos/mod.rs b/studio/src/interaction/gizmos/mod.rs index 1a4c0fc..5ed674d 100644 --- a/studio/src/interaction/gizmos/mod.rs +++ b/studio/src/interaction/gizmos/mod.rs @@ -11,6 +11,7 @@ use self::{ rotation::{spawn_rotation_gizmo, update_ss_ring_rotation}, translation::spawn_translation_gizmo, }; +pub use common::TransformGizmo; use super::{Selection, TransformMode, TransformType}; diff --git a/studio/src/wasm/screenshot.rs b/studio/src/wasm/screenshot.rs index b4141c4..78e99d8 100644 --- a/studio/src/wasm/screenshot.rs +++ b/studio/src/wasm/screenshot.rs @@ -13,6 +13,8 @@ use bevy::{prelude::*, render::view::screenshot::ScreenshotManager, window::Prim use image::{codecs::png::PngEncoder, ColorType, ImageEncoder}; use wasm_bindgen::prelude::{wasm_bindgen, JsValue}; +use crate::{interaction::gizmos::TransformGizmo, world_grid::WorldGridPlane}; + use super::{AsJsValue, StaticBuffer, WasmMessageBuffer}; static SCREENSHOT_REQUEST: WasmMessageBuffer<()> = WasmMessageBuffer::new(); @@ -22,16 +24,25 @@ pub struct ScreenshotPlugin; impl Plugin for ScreenshotPlugin { fn build(&self, app: &mut App) { + app.add_event::(); app.add_systems( Update, ( - take_screenshots.map(bevy::utils::error), + ( + prepare_screenshot, + apply_deferred, + take_screenshots.map(bevy::utils::error), + ) + .chain(), send_screenshots.map(bevy::utils::error), ), ); } } +#[derive(Event)] +pub struct ScreenshotRequestedEvent; + #[wasm_bindgen] #[derive(Clone)] pub struct Screenshot { @@ -74,21 +85,46 @@ impl AsJsValue for Screenshot { #[wasm_bindgen(js_name = requestScreenshot)] pub fn request_screenshot() { + info!("[wasm::screenshot] Screenshot request received"); SCREENSHOT_REQUEST.write_message(()); } +fn prepare_screenshot( + mut q_editor_visuals: Query<&mut Visibility, Or<(With, With)>>, + mut ew: EventWriter, +) { + if SCREENSHOT_REQUEST.take_message().is_none() { + return; + } + + info!( + "[wasm::screenshot] Hiding {} editor visuals", + q_editor_visuals.iter().count() + ); + + for mut visibility in q_editor_visuals.iter_mut() { + *visibility = Visibility::Hidden; + } + + ew.send(ScreenshotRequestedEvent); +} + fn take_screenshots( mut r_screenshot_mgr: ResMut, q_window: Query>, + mut er: EventReader, ) -> Result<(), String> { - if SCREENSHOT_REQUEST.take_message().is_none() { + if er.is_empty() { return Ok(()); } - let Ok(window_ent) = q_window.get_single() else { return Ok(()); }; + er.clear(); + + info!("[wasm::screenshot] Queueing screenshot request"); + r_screenshot_mgr .take_screenshot(window_ent, |img| { let img = match img.try_into_dynamic().map(|img| img.to_rgb8()) { @@ -146,7 +182,10 @@ declare global { } "#; -fn send_screenshots(q_window: Query<&Window, With>) -> Result<(), String> { +fn send_screenshots( + q_window: Query<&Window, With>, + mut q_editor_visuals: Query<&mut Visibility, Or<(With, With)>>, +) -> Result<(), String> { let Some(screenshot) = SCREENSHOT.take_message() else { return Ok(()); }; @@ -157,5 +196,16 @@ fn send_screenshots(q_window: Query<&Window, With>) -> Result<(), let screenshot = Screenshot::from(screenshot); - super::dispatch_to_js(window, "screenshot-ready", &screenshot) + super::dispatch_to_js(window, "screenshot-ready", &screenshot)?; + + info!( + "[wasm::screenshot] Revealing {} previously hidden editor visuals", + q_editor_visuals.iter().count() + ); + + for mut visibility in q_editor_visuals.iter_mut() { + *visibility = Visibility::Inherited; + } + + Ok(()) } diff --git a/studio/src/world_grid.rs b/studio/src/world_grid.rs index 8146db4..2c3256e 100644 --- a/studio/src/world_grid.rs +++ b/studio/src/world_grid.rs @@ -17,7 +17,7 @@ impl Plugin for WorldGridPlugin { } #[derive(Component)] -struct WorldGridPlane; +pub struct WorldGridPlane; #[derive(Asset, AsBindGroup, TypePath, Clone)] struct ProceduralGridMaterial {}