From d05d0d0f865fe2e0afe354928f7b3c7977859514 Mon Sep 17 00:00:00 2001 From: 443eb9 <443eb9@gmail.com> Date: Thu, 21 Nov 2024 17:51:32 +0800 Subject: [PATCH 01/10] feat: Initial framework. --- bevy_editor_panes/bevy_asset_browser/Cargo.toml | 1 + bevy_editor_panes/bevy_asset_browser/src/lib.rs | 9 ++++++++- .../src/ui/directory_content.rs | 2 +- .../bevy_asset_browser/src/ui/nodes.rs | 5 +++++ crates/bevy_asset_preview/src/lib.rs | 15 +++++++++++++++ crates/bevy_asset_preview/src/render/mod.rs | 0 crates/bevy_asset_preview/src/sprite/mod.rs | 9 +++++++++ crates/bevy_editor/src/lib.rs | 2 +- crates/bevy_infinite_grid/src/render/mod.rs | 0 9 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 crates/bevy_asset_preview/src/render/mod.rs create mode 100644 crates/bevy_asset_preview/src/sprite/mod.rs mode change 100755 => 100644 crates/bevy_infinite_grid/src/render/mod.rs diff --git a/bevy_editor_panes/bevy_asset_browser/Cargo.toml b/bevy_editor_panes/bevy_asset_browser/Cargo.toml index f6d0c58f..e1a22eb9 100644 --- a/bevy_editor_panes/bevy_asset_browser/Cargo.toml +++ b/bevy_editor_panes/bevy_asset_browser/Cargo.toml @@ -12,6 +12,7 @@ bevy_pane_layout.workspace = true bevy_scroll_box.workspace = true bevy_context_menu.workspace = true atomicow.workspace = true +bevy_asset_preview.workspace = true [lints] workspace = true diff --git a/bevy_editor_panes/bevy_asset_browser/src/lib.rs b/bevy_editor_panes/bevy_asset_browser/src/lib.rs index ea0e417b..0878921c 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/lib.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/lib.rs @@ -11,6 +11,7 @@ use bevy::{ }, prelude::*, }; +use bevy_asset_preview::AssetPreviewPlugin; use bevy_pane_layout::PaneRegistry; use bevy_scroll_box::ScrollBoxPlugin; use ui::{top_bar::location_as_changed, AssetBrowserNode}; @@ -19,7 +20,9 @@ mod io; mod ui; /// The bevy asset browser plugin -pub struct AssetBrowserPanePlugin; +pub struct AssetBrowserPanePlugin { + pub preview: bool, +} impl Plugin for AssetBrowserPanePlugin { fn build(&self, app: &mut App) { @@ -27,6 +30,10 @@ impl Plugin for AssetBrowserPanePlugin { embedded_asset!(app, "assets/source_icon.png"); embedded_asset!(app, "assets/file_icon.png"); + if self.preview { + app.add_plugins(AssetPreviewPlugin); + } + app.world_mut() .get_resource_or_init::() .register("Asset Browser", |mut commands, pane_root| { diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs index d51f4c66..e65a05e2 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs @@ -127,7 +127,7 @@ fn populate_directory_content( .set_parent(parent_entity); } Entry::File(name) => { - spawn_file_node(commands, name.clone(), asset_server, theme) + spawn_file_node(commands, name.clone(), asset_server, location, theme) .set_parent(parent_entity); } } diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs index e5d16c1e..ec40d6ea 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs @@ -14,6 +14,9 @@ use crate::{io, ui::source_id_to_string, AssetBrowserLocation}; use super::{directory_content::delete_folder, DEFAULT_SOURCE_ID_NAME}; +#[derive(Component)] +pub struct RequestPreview; + pub(crate) fn spawn_source_node<'a>( commands: &'a mut Commands, source_id: &AssetSourceId, @@ -153,6 +156,7 @@ pub(crate) fn spawn_file_node<'a>( commands: &'a mut Commands, file_name: String, asset_server: &Res, + location: &Res, theme: &Res, ) -> EntityCommands<'a> { let base_node = spawn_base_node(commands, theme).id(); @@ -165,6 +169,7 @@ pub(crate) fn spawn_file_node<'a>( height: Val::Px(50.0), ..default() }, + RequestPreview, )) .set_parent(base_node); // Folder Name diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index 45574a5b..cf1dcc54 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -1,5 +1,8 @@ use bevy::prelude::*; +mod render; +mod sprite; + /// This crate is a work in progress and is not yet ready for use. /// The intention is to provide a way to load/render/unload assets in the background and provide previews of them in the Bevy Editor. /// For 2d assets this will be a simple sprite, for 3d assets this will require a quick render of the asset at a low resolution, just enough for a user to be able to tell quickly what it is. @@ -7,6 +10,18 @@ use bevy::prelude::*; /// So long as the assets are unchanged, the previews will be cached and will not need to be re-rendered. /// In theory this can be done passively in the background, and the previews will be ready when the user needs them. +#[derive(Component)] +pub enum RequestPreview { + /// A simple sprite image. + Image(Handle), + + /// A 2d mesh. + Mesh2d(Handle), + + /// A 3d mesh like a character. + Mesh3d(Handle), +} + pub struct AssetPreviewPlugin; impl Plugin for AssetPreviewPlugin { diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs new file mode 100644 index 00000000..e69de29b diff --git a/crates/bevy_asset_preview/src/sprite/mod.rs b/crates/bevy_asset_preview/src/sprite/mod.rs new file mode 100644 index 00000000..6b9a0468 --- /dev/null +++ b/crates/bevy_asset_preview/src/sprite/mod.rs @@ -0,0 +1,9 @@ +use bevy::app::{App, Plugin}; + +// TODO: support sprite atlas, and document this. +/// Handles the preview for sprites. +pub struct SpriteAssetPreviewPlugin; + +impl Plugin for SpriteAssetPreviewPlugin { + fn build(&self, app: &mut App) {} +} diff --git a/crates/bevy_editor/src/lib.rs b/crates/bevy_editor/src/lib.rs index 8d8685a6..21cd138c 100644 --- a/crates/bevy_editor/src/lib.rs +++ b/crates/bevy_editor/src/lib.rs @@ -54,7 +54,7 @@ impl Plugin for EditorPlugin { Viewport2dPanePlugin, Viewport3dPanePlugin, ui::EditorUIPlugin, - AssetBrowserPanePlugin, + AssetBrowserPanePlugin { preview: true }, LoadGltfPlugin, )) .add_systems(Startup, dummy_setup); diff --git a/crates/bevy_infinite_grid/src/render/mod.rs b/crates/bevy_infinite_grid/src/render/mod.rs old mode 100755 new mode 100644 From c4e646600b3e04670726ebd53a353b9b0d18ebfd Mon Sep 17 00:00:00 2001 From: 443eb9 <443eb9@gmail.com> Date: Thu, 21 Nov 2024 18:45:11 +0800 Subject: [PATCH 02/10] deps: Bumped to 0.15.0-rc.3 --- Cargo.toml | 4 +-- bevy_editor_panes/bevy_2d_viewport/src/lib.rs | 2 +- bevy_editor_panes/bevy_3d_viewport/src/lib.rs | 4 +-- .../bevy_asset_browser/src/ui/nodes.rs | 29 ++++++++++--------- bevy_widgets/bevy_menu_bar/src/lib.rs | 2 +- crates/bevy_asset_preview/src/lib.rs | 12 ++------ crates/bevy_asset_preview/src/render/mod.rs | 10 +++++++ crates/bevy_asset_preview/src/sprite/mod.rs | 9 ------ crates/bevy_asset_preview/src/ui.rs | 25 ++++++++++++++++ 9 files changed, 60 insertions(+), 37 deletions(-) delete mode 100644 crates/bevy_asset_preview/src/sprite/mod.rs create mode 100644 crates/bevy_asset_preview/src/ui.rs diff --git a/Cargo.toml b/Cargo.toml index 7e57d616..6ba3fef0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,8 +27,8 @@ unsafe_op_in_unsafe_fn = "warn" unused_qualifications = "warn" [workspace.dependencies] -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "015f2c69ca2a2c009fd04eadada282482deaf469", features = ["wayland"] } -bevy_derive = { git = "https://github.com/bevyengine/bevy.git", rev = "015f2c69ca2a2c009fd04eadada282482deaf469" } +bevy = { version = "0.15.0-rc.3", features = ["wayland"] } +bevy_derive = { version = "0.15.0-rc.3" } thiserror = "1" serde = { version = "1", features = ["derive"] } atomicow = "1.0.0" diff --git a/bevy_editor_panes/bevy_2d_viewport/src/lib.rs b/bevy_editor_panes/bevy_2d_viewport/src/lib.rs index 4a80ecfa..e66c02df 100644 --- a/bevy_editor_panes/bevy_2d_viewport/src/lib.rs +++ b/bevy_editor_panes/bevy_2d_viewport/src/lib.rs @@ -104,7 +104,7 @@ fn on_pane_creation( let image_id = commands .spawn(( UiImage { - texture: image_handle.clone(), + image: image_handle.clone(), ..Default::default() }, Node { diff --git a/bevy_editor_panes/bevy_3d_viewport/src/lib.rs b/bevy_editor_panes/bevy_3d_viewport/src/lib.rs index 1621957e..d5e7fb9f 100644 --- a/bevy_editor_panes/bevy_3d_viewport/src/lib.rs +++ b/bevy_editor_panes/bevy_3d_viewport/src/lib.rs @@ -106,7 +106,7 @@ fn render_target_picking_passthrough( let new_location = Location { position: event.location.position - node_rect.min, - target: NormalizedRenderTarget::Image(ui_image.texture.clone()), + target: NormalizedRenderTarget::Image(ui_image.image.clone()), }; // Duplicate the event @@ -166,7 +166,7 @@ fn on_pane_creation( commands .spawn(( UiImage { - texture: image_handle.clone(), + image: image_handle.clone(), ..Default::default() }, Node { diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs index ec40d6ea..bdd69282 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs @@ -7,6 +7,7 @@ use bevy::{ window::SystemCursorIcon, winit::cursor::CursorIcon, }; +use bevy_asset_preview::RequestPreview; use bevy_context_menu::{ContextMenu, ContextMenuOption}; use bevy_editor_styles::Theme; @@ -14,9 +15,6 @@ use crate::{io, ui::source_id_to_string, AssetBrowserLocation}; use super::{directory_content::delete_folder, DEFAULT_SOURCE_ID_NAME}; -#[derive(Component)] -pub struct RequestPreview; - pub(crate) fn spawn_source_node<'a>( commands: &'a mut Commands, source_id: &AssetSourceId, @@ -162,16 +160,21 @@ pub(crate) fn spawn_file_node<'a>( let base_node = spawn_base_node(commands, theme).id(); // Icon - commands - .spawn(( - UiImage::new(asset_server.load("embedded://bevy_asset_browser/assets/file_icon.png")), - Node { - height: Val::Px(50.0), - ..default() - }, - RequestPreview, - )) - .set_parent(base_node); + let mut icon = commands.spawn_empty(); + let icon_entity = icon.id(); + icon.insert(( + // RequestPreview { + // target: icon_entity, + // asset: asset_server + // .load::<()>(location.path.join(&file_name)) + // .untyped(), + // }, + Node { + height: Val::Px(50.0), + ..default() + }, + )) + .set_parent(base_node); // Folder Name commands .spawn(( diff --git a/bevy_widgets/bevy_menu_bar/src/lib.rs b/bevy_widgets/bevy_menu_bar/src/lib.rs index 57472aae..bbfb02c4 100644 --- a/bevy_widgets/bevy_menu_bar/src/lib.rs +++ b/bevy_widgets/bevy_menu_bar/src/lib.rs @@ -69,7 +69,7 @@ fn menu_setup( let logo = commands .spawn(UiImage { - texture: asset_server.load("embedded://bevy_menu_bar/assets/logo/bevy_logo.png"), + image: asset_server.load("embedded://bevy_menu_bar/assets/logo/bevy_logo.png"), ..Default::default() }) .id(); diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index cf1dcc54..7c25141b 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; mod render; -mod sprite; +mod ui; /// This crate is a work in progress and is not yet ready for use. /// The intention is to provide a way to load/render/unload assets in the background and provide previews of them in the Bevy Editor. @@ -12,18 +12,12 @@ mod sprite; #[derive(Component)] pub enum RequestPreview { - /// A simple sprite image. Image(Handle), - - /// A 2d mesh. - Mesh2d(Handle), - - /// A 3d mesh like a character. - Mesh3d(Handle), + Mesh(Handle), } pub struct AssetPreviewPlugin; impl Plugin for AssetPreviewPlugin { - fn build(&self, _app: &mut App) {} + fn build(&self, app: &mut App) {} } diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index e69de29b..ba4e83b2 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -0,0 +1,10 @@ +use bevy::{ + asset::Handle, + prelude::{Deref, DerefMut, Image, Mesh, Resource}, + utils::HashMap, +}; + +/// Meshes that are rendered for preview purpose. This should be inserted into +/// main world. +#[derive(Resource, Default, Deref, DerefMut)] +pub struct PrerenderedMesh(HashMap, Handle>); diff --git a/crates/bevy_asset_preview/src/sprite/mod.rs b/crates/bevy_asset_preview/src/sprite/mod.rs deleted file mode 100644 index 6b9a0468..00000000 --- a/crates/bevy_asset_preview/src/sprite/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -use bevy::app::{App, Plugin}; - -// TODO: support sprite atlas, and document this. -/// Handles the preview for sprites. -pub struct SpriteAssetPreviewPlugin; - -impl Plugin for SpriteAssetPreviewPlugin { - fn build(&self, app: &mut App) {} -} diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs new file mode 100644 index 00000000..4bec932f --- /dev/null +++ b/crates/bevy_asset_preview/src/ui.rs @@ -0,0 +1,25 @@ +use std::any::TypeId; + +use bevy::{ + asset::AssetServer, + prelude::{Commands, Entity, EventReader, Image, Mesh, Query, Res}, + ui::UiImage, +}; + +use crate::{render::PrerenderedMesh, RequestPreview}; + +const FILE_PLACEHOLDER: &'static str = "embedded://bevy_asset_browser/assets/file_icon.png"; + +pub fn preview_handler( + mut commands: Commands, + mut requests_query: Query<(Entity, &RequestPreview, Option<&mut UiImage>)>, + asset_server: Res, + prerendered: Res, +) { + for (entity, request, reuseable_image) in &mut requests_query { + // let preview = match request { + // RequestPreview::Image(handle) => handle.clone(), + // RequestPreview::Mesh(handle) => prerendered.get(handle), + // }; + } +} From 9e066cff8613de36028c145c63a189a804ede9b8 Mon Sep 17 00:00:00 2001 From: 443eb9 <443eb9@gmail.com> Date: Fri, 22 Nov 2024 19:27:26 +0800 Subject: [PATCH 03/10] wip --- crates/bevy_asset_preview/src/lib.rs | 13 +++- crates/bevy_asset_preview/src/render/mod.rs | 85 +++++++++++++++++++-- crates/bevy_asset_preview/src/ui.rs | 37 ++++++--- 3 files changed, 119 insertions(+), 16 deletions(-) diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index 7c25141b..c55206ed 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -1,4 +1,9 @@ -use bevy::prelude::*; +use bevy::{ + prelude::*, + render::{extract_component::ExtractComponentPlugin, extract_resource::ExtractResourcePlugin}, +}; + +use crate::render::{PrerenderMesh, PrerenderedMeshes}; mod render; mod ui; @@ -19,5 +24,9 @@ pub enum RequestPreview { pub struct AssetPreviewPlugin; impl Plugin for AssetPreviewPlugin { - fn build(&self, app: &mut App) {} + fn build(&self, app: &mut App) { + app.add_systems(Startup, render::setup_prerender_scene) + .add_systems(Update, (render::flush_queue, ui::preview_handler)) + .init_resource::(); + } } diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index ba4e83b2..d9aed009 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -1,10 +1,85 @@ +use std::collections::VecDeque; + use bevy::{ - asset::Handle, - prelude::{Deref, DerefMut, Image, Mesh, Resource}, - utils::HashMap, + asset::{AssetId, Assets, Handle}, + core_pipeline::core_3d::MainOpaquePass3dNode, + ecs::{query::QueryItem, system::lifetimeless::Read}, + pbr::{MeshMaterial3d, StandardMaterial}, + prelude::{ + Camera, Camera3d, Commands, Component, Deref, FromWorld, Image, Mesh, Mesh3d, Query, + QueryState, Res, ResMut, Resource, World, + }, + render::{ + camera::RenderTarget, + extract_component::ExtractComponent, + extract_resource::ExtractResource, + render_graph::{Node, NodeRunError, RenderGraphContext, ViewNode}, + renderer::RenderContext, + view::RenderLayers, + }, + utils::{Entry, HashMap, HashSet}, }; +pub const PRERENDER_LAYER: RenderLayers = RenderLayers::layer(63); + +#[derive(Component, Clone)] +pub struct PrerenderMesh; + +#[derive(Component)] +pub struct PrerendererView; + +pub fn setup_prerender_scene(mut commands: Commands) { + commands.spawn(( + Camera3d::default(), + Camera { + target: RenderTarget::Image(Handle::default()), + ..Default::default() + }, + PRERENDER_LAYER, + )); +} + /// Meshes that are rendered for preview purpose. This should be inserted into /// main world. -#[derive(Resource, Default, Deref, DerefMut)] -pub struct PrerenderedMesh(HashMap, Handle>); +#[derive(Resource, Default)] +pub struct PrerenderedMeshes { + rendered: HashMap, Handle>, + queue: VecDeque>, +} + +impl PrerenderedMeshes { + pub fn get_or_schedule(&mut self, handle: Handle) -> Option> { + let id = handle.id(); + match self.rendered.entry(id) { + Entry::Occupied(e) => Some(e.get().clone()), + Entry::Vacant(_) => { + self.queue.push_back(handle); + None + } + } + } +} + +#[derive(Resource, Deref)] +pub struct PrerenderedMeshMaterial(MeshMaterial3d); + +impl FromWorld for PrerenderedMeshMaterial { + fn from_world(world: &mut World) -> Self { + // TODO materialize once user applied material or detected material in model + Self(MeshMaterial3d( + world + .resource_mut::>() + .add(StandardMaterial::default()), + )) + } +} + +pub(crate) fn flush_queue( + mut commands: Commands, + mut meshes: ResMut, + default_material: Res, +) { + let Some(mesh) = meshes.queue.pop_front() else { + return; + }; +} diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs index 4bec932f..618aab60 100644 --- a/crates/bevy_asset_preview/src/ui.rs +++ b/crates/bevy_asset_preview/src/ui.rs @@ -1,12 +1,10 @@ -use std::any::TypeId; - use bevy::{ asset::AssetServer, - prelude::{Commands, Entity, EventReader, Image, Mesh, Query, Res}, + prelude::{Commands, Entity, Query, Res, ResMut}, ui::UiImage, }; -use crate::{render::PrerenderedMesh, RequestPreview}; +use crate::{render::PrerenderedMeshes, RequestPreview}; const FILE_PLACEHOLDER: &'static str = "embedded://bevy_asset_browser/assets/file_icon.png"; @@ -14,12 +12,33 @@ pub fn preview_handler( mut commands: Commands, mut requests_query: Query<(Entity, &RequestPreview, Option<&mut UiImage>)>, asset_server: Res, - prerendered: Res, + mut prerendered: ResMut, ) { for (entity, request, reuseable_image) in &mut requests_query { - // let preview = match request { - // RequestPreview::Image(handle) => handle.clone(), - // RequestPreview::Mesh(handle) => prerendered.get(handle), - // }; + let preview = match request { + RequestPreview::Image(handle) => { + commands.entity(entity).remove::(); + handle.clone() + } + RequestPreview::Mesh(handle) => { + if let Some(handle) = prerendered.get_or_schedule(handle.clone()) { + commands.entity(entity).remove::(); + handle + } else { + // Not rendered yet, fall back to default. + asset_server.load(FILE_PLACEHOLDER) + } + } + }; + + if let Some(mut reuseable) = reuseable_image { + reuseable.image = preview; + } else { + // TODO: sprite atlas. + commands.entity(entity).insert(UiImage { + image: preview, + ..Default::default() + }); + } } } From 2349976986d661bef15b056cb4d7901528bdbb27 Mon Sep 17 00:00:00 2001 From: 443eb9 <443eb9@gmail.com> Date: Sat, 23 Nov 2024 08:44:03 +0800 Subject: [PATCH 04/10] wip --- .../bevy_asset_browser/src/lib.rs | 1 + .../bevy_asset_browser/src/ui/nodes.rs | 26 +- crates/bevy_asset_preview/src/lib.rs | 51 ++- crates/bevy_asset_preview/src/render/mod.rs | 290 +++++++++++++++++- crates/bevy_asset_preview/src/ui.rs | 45 ++- crates/bevy_editor_launcher/assets/chair.glb | Bin 0 -> 16180 bytes crates/bevy_editor_launcher/assets/cube.glb | Bin 0 -> 1936 bytes 7 files changed, 377 insertions(+), 36 deletions(-) create mode 100644 crates/bevy_editor_launcher/assets/chair.glb create mode 100644 crates/bevy_editor_launcher/assets/cube.glb diff --git a/bevy_editor_panes/bevy_asset_browser/src/lib.rs b/bevy_editor_panes/bevy_asset_browser/src/lib.rs index 0878921c..86fc2534 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/lib.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/lib.rs @@ -21,6 +21,7 @@ mod ui; /// The bevy asset browser plugin pub struct AssetBrowserPanePlugin { + /// Enable asset preview or not. pub preview: bool, } diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs index bdd69282..97dad2cc 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs @@ -7,7 +7,7 @@ use bevy::{ window::SystemCursorIcon, winit::cursor::CursorIcon, }; -use bevy_asset_preview::RequestPreview; +use bevy_asset_preview::PreviewAsset; use bevy_context_menu::{ContextMenu, ContextMenuOption}; use bevy_editor_styles::Theme; @@ -160,21 +160,15 @@ pub(crate) fn spawn_file_node<'a>( let base_node = spawn_base_node(commands, theme).id(); // Icon - let mut icon = commands.spawn_empty(); - let icon_entity = icon.id(); - icon.insert(( - // RequestPreview { - // target: icon_entity, - // asset: asset_server - // .load::<()>(location.path.join(&file_name)) - // .untyped(), - // }, - Node { - height: Val::Px(50.0), - ..default() - }, - )) - .set_parent(base_node); + commands + .spawn(( + PreviewAsset::new(location.path.join(&file_name), asset_server), + Node { + height: Val::Px(50.0), + ..default() + }, + )) + .set_parent(base_node); // Folder Name commands .spawn(( diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index 7c25141b..3bdd319a 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -1,4 +1,14 @@ -use bevy::prelude::*; +use bevy::{ + app::{App, Plugin, Startup, Update}, + asset::{AssetPath, AssetServer, Handle}, + gltf::GltfAssetLabel, + prelude::{Component, Image, Mesh}, + scene::Scene, +}; + +use crate::render::{ + PrerenderedScenes, PreviewRenderLayers, PreviewRendered, PreviewSceneState, PreviewSettings, +}; mod render; mod ui; @@ -11,13 +21,46 @@ mod ui; /// In theory this can be done passively in the background, and the previews will be ready when the user needs them. #[derive(Component)] -pub enum RequestPreview { +pub enum PreviewAsset { Image(Handle), - Mesh(Handle), + Scene(Handle), + Other, +} + +impl PreviewAsset { + pub fn new<'a>(path: impl Into>, asset_server: &AssetServer) -> Self { + let path = <_ as Into>>::into(path); + match path.path().extension() { + Some(ext) => match ext.to_str().unwrap() { + "png" => Self::Image(asset_server.load(path)), + "glb" => Self::Scene( + asset_server + .load(GltfAssetLabel::Scene(0).from_asset(path.path().to_path_buf())), + ), + _ => Self::Other, + }, + None => Self::Other, + } + } } pub struct AssetPreviewPlugin; impl Plugin for AssetPreviewPlugin { - fn build(&self, app: &mut App) {} + fn build(&self, app: &mut App) { + app.add_event::() + .add_systems( + Update, + ( + render::update_queue, + render::update_preview_frames_counter, + render::change_render_layers, + ui::preview_handler, + ), + ) + .init_resource::() + .init_resource::() + .init_resource::() + .init_resource::(); + } } diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index ba4e83b2..b148527b 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -1,10 +1,288 @@ +use std::collections::VecDeque; + use bevy::{ - asset::Handle, - prelude::{Deref, DerefMut, Image, Mesh, Resource}, - utils::HashMap, + app::{App, First, Main, MainSchedulePlugin, PluginsState, Update}, + asset::{AssetId, AssetPlugin, AssetServer, Assets, Handle}, + core::{FrameCountPlugin, TaskPoolPlugin, TypeRegistrationPlugin}, + core_pipeline::CorePipelinePlugin, + diagnostic::LogDiagnosticsPlugin, + ecs::{ + entity::EntityHashMap, + event::{event_update_condition, event_update_system, EventUpdates}, + query::QuerySingleError, + schedule::ScheduleLabel, + world, + }, + gltf::GltfAssetLabel, + log::{error, info, LogPlugin}, + math::{UVec2, Vec3}, + pbr::{DirectionalLight, MeshMaterial3d, PbrPlugin, StandardMaterial}, + prelude::{ + AppTypeRegistry, Camera, Camera3d, Commands, Component, Deref, DerefMut, + DespawnRecursiveExt, Entity, Event, EventReader, EventWriter, FromWorld, Image, + ImagePlugin, IntoSystemConfigs, Mesh, Mesh3d, NonSendMut, PluginGroup, Query, Res, ResMut, + Resource, Transform, With, World, + }, + render::{ + camera::RenderTarget, + pipelined_rendering::PipelinedRenderingPlugin, + render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages}, + renderer::RenderDevice, + view::RenderLayers, + Extract, ExtractSchedule, RenderApp, RenderPlugin, + }, + scene::{InstanceId, Scene, SceneInstance, SceneRoot, SceneSpawner}, + time::TimePlugin, + ui::{IsDefaultUiCamera, TargetCamera}, + utils::{Entry, HashMap, HashSet}, + window::{WindowClosing, WindowCreated, WindowPlugin, WindowResized}, + winit::WinitPlugin, + DefaultPlugins, MinimalPlugins, }; -/// Meshes that are rendered for preview purpose. This should be inserted into +use crate::PreviewAsset; + +pub const BASE_PREVIEW_LAYER: usize = 128; +pub const PREVIEW_LAYERS_COUNT: usize = 8; +pub const PREVIEW_RENDER_FRAMES: u32 = 32; + +#[derive(Resource)] +pub struct PreviewRenderLayers { + available: u64, +} + +impl Default for PreviewRenderLayers { + fn default() -> Self { + Self { available: !0 } + } +} + +impl PreviewRenderLayers { + pub fn occupy(&mut self) -> Option { + if self.is_full() { + None + } else { + let n = self.available.trailing_zeros() as usize; + self.available &= !(1 << n); + Some(n) + } + } + + pub fn free(&mut self, layer: RenderLayers) { + for b in layer.iter() { + self.available &= !(1 << b); + } + } + + pub fn is_full(&self) -> bool { + self.available.trailing_zeros() == PREVIEW_LAYERS_COUNT as u32 + } +} + +#[derive(Resource)] +pub struct PreviewSettings { + pub resolution: UVec2, +} + +impl Default for PreviewSettings { + fn default() -> Self { + Self { + resolution: UVec2::splat(256), + } + } +} + +fn create_prerender_target(settings: &PreviewSettings) -> Image { + let mut image = Image::new_fill( + Extent3d { + width: settings.resolution.x, + height: settings.resolution.y, + depth_or_array_layers: 1, + }, + TextureDimension::D2, + &[255, 0, 0, 255], + TextureFormat::Bgra8UnormSrgb, + Default::default(), + ); + + image.texture_descriptor.usage |= + TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST | TextureUsages::RENDER_ATTACHMENT; + + image +} + +#[derive(Component)] +pub struct PreviewRenderView { + pub layer: usize, +} + +#[derive(Component, Default)] +pub struct PreviewRenderedFrames { + pub cur_frame: u32, +} + +#[derive(Event)] +pub struct PreviewRendered { + pub layer: usize, +} + +#[derive(Resource)] +pub struct PreviewSceneState { + cameras: [Entity; PREVIEW_LAYERS_COUNT], + handles: [Handle; PREVIEW_LAYERS_COUNT], + instances: [Option; PREVIEW_LAYERS_COUNT], + applied_layer: [bool; PREVIEW_LAYERS_COUNT], +} + +impl FromWorld for PreviewSceneState { + fn from_world(world: &mut World) -> Self { + let mut cameras = [Entity::PLACEHOLDER; PREVIEW_LAYERS_COUNT]; + + for i in 0..PREVIEW_LAYERS_COUNT { + world.spawn(( + DirectionalLight::default(), + Transform::IDENTITY.looking_to(Vec3::new(1.0, -1.0, 1.0), Vec3::Y), + RenderLayers::from_layers(&[i + BASE_PREVIEW_LAYER]), + )); + + cameras[i] = world + .spawn(( + Camera3d::default(), + Camera { + target: RenderTarget::Image(Handle::default()), + is_active: false, + ..Default::default() + }, + Transform::from_translation(Vec3::new(-5.0, 2.0, -5.0)) + .looking_at(Vec3::ZERO, Vec3::Y), + PreviewRenderView { layer: i }, + RenderLayers::from_layers(&[i + BASE_PREVIEW_LAYER]), + )) + .id(); + } + + Self { + cameras, + handles: std::array::from_fn(|_| Handle::default()), + instances: [None; PREVIEW_LAYERS_COUNT], + applied_layer: [false; PREVIEW_LAYERS_COUNT], + } + } +} + +/// Scenes that are rendered for preview purpose. This should be inserted into /// main world. -#[derive(Resource, Default, Deref, DerefMut)] -pub struct PrerenderedMesh(HashMap, Handle>); +#[derive(Resource, Default)] +pub struct PrerenderedScenes { + rendered: HashMap, Handle>, + rendering: HashSet>, + queue: HashSet>, +} + +impl PrerenderedScenes { + pub fn get_or_schedule(&mut self, handle: Handle) -> Option> { + let id = handle.id(); + match self.rendered.entry(id) { + Entry::Occupied(e) => Some(e.get().clone()), + Entry::Vacant(_) => { + if !self.rendering.contains(&id) { + self.queue.insert(handle); + self.rendering.insert(id); + } + None + } + } + } +} + +pub(crate) fn update_queue( + mut commands: Commands, + mut prerendered: ResMut, + mut render_layers: ResMut, + mut scene_spawner: ResMut, + mut scene_state: ResMut, + mut camera_query: Query<&mut Camera, With>, + settings: Res, + mut images: ResMut>, + mut preview_rendered: EventReader, +) { + while !render_layers.is_full() { + let Some(handle) = prerendered.queue.iter().nth(0).take().cloned() else { + dbg!(); + break; + }; + dbg!(&handle); + + let instance = scene_spawner.spawn(handle.clone()); + let layer = render_layers.occupy().unwrap(); + scene_state.handles[layer] = handle; + scene_state.instances[layer] = Some(instance); + scene_state.applied_layer[layer] = false; + + let camera_entity = scene_state.cameras[layer]; + let mut camera = camera_query.get_mut(camera_entity).unwrap(); + camera.is_active = true; + camera.target = RenderTarget::Image(images.add(create_prerender_target(&settings))); + commands + .entity(camera_entity) + .insert(PreviewRenderedFrames::default()); + } + + for finished in preview_rendered.read() { + let mut camera = camera_query + .get_mut(scene_state.cameras[finished.layer]) + .unwrap(); + camera.is_active = false; + let RenderTarget::Image(target) = &camera.target else { + unreachable!() + }; + + render_layers.free(RenderLayers::from_layers(&[finished.layer])); + let handle = scene_state.handles[finished.layer].clone(); + dbg!(&handle); + prerendered.rendering.remove(&handle.id()); + prerendered.rendered.insert(handle.id(), target.clone()); + } +} + +pub(crate) fn update_preview_frames_counter( + mut commands: Commands, + mut counters_query: Query<(Entity, &mut PreviewRenderedFrames, &PreviewRenderView)>, + mut preview_rendered: EventWriter, + scene_state: Res, + scene_spawner: Res, +) { + for (entity, mut cnt, view) in &mut counters_query { + if scene_state.instances[view.layer] + .is_some_and(|inst| scene_spawner.instance_is_ready(inst)) + { + cnt.cur_frame += 1; + + if cnt.cur_frame >= PREVIEW_RENDER_FRAMES { + commands.entity(entity).remove::(); + preview_rendered.send(PreviewRendered { layer: view.layer }); + } + } + } +} + +pub(crate) fn change_render_layers( + mut commands: Commands, + mut scene_state: ResMut, + scene_spawner: Res, +) { + for layer in 0..PREVIEW_LAYERS_COUNT { + if let Some(instance) = scene_state.instances[layer] { + if !scene_state.applied_layer[layer] && scene_spawner.instance_is_ready(instance) { + scene_state.applied_layer[layer] = true; + + commands.insert_batch( + scene_spawner + .iter_instance_entities(instance) + .map(|e| (e, RenderLayers::from_layers(&[layer + BASE_PREVIEW_LAYER]))) + .collect::>(), + ); + } + } + } +} diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs index 4bec932f..45d1465b 100644 --- a/crates/bevy_asset_preview/src/ui.rs +++ b/crates/bevy_asset_preview/src/ui.rs @@ -1,25 +1,50 @@ -use std::any::TypeId; - use bevy::{ asset::AssetServer, - prelude::{Commands, Entity, EventReader, Image, Mesh, Query, Res}, + gltf::GltfAssetLabel, + prelude::{Commands, Entity, Query, Res, ResMut}, ui::UiImage, }; -use crate::{render::PrerenderedMesh, RequestPreview}; +use crate::{render::PrerenderedScenes, PreviewAsset}; const FILE_PLACEHOLDER: &'static str = "embedded://bevy_asset_browser/assets/file_icon.png"; +// TODO: handle assets modification pub fn preview_handler( mut commands: Commands, - mut requests_query: Query<(Entity, &RequestPreview, Option<&mut UiImage>)>, + mut requests_query: Query<(Entity, &PreviewAsset, Option<&mut UiImage>)>, asset_server: Res, - prerendered: Res, + mut prerendered: ResMut, ) { for (entity, request, reuseable_image) in &mut requests_query { - // let preview = match request { - // RequestPreview::Image(handle) => handle.clone(), - // RequestPreview::Mesh(handle) => prerendered.get(handle), - // }; + let preview = match request { + PreviewAsset::Image(handle) => { + commands.entity(entity).remove::(); + handle.clone() + } + PreviewAsset::Scene(handle) => { + if let Some(handle) = prerendered.get_or_schedule(handle.clone()) { + commands.entity(entity).remove::(); + handle + } else { + // Not rendered yet, fall back to default. + asset_server.load(FILE_PLACEHOLDER) + } + } + PreviewAsset::Other => { + commands.entity(entity).remove::(); + asset_server.load(FILE_PLACEHOLDER) + } + }; + + if let Some(mut reuseable) = reuseable_image { + reuseable.image = preview; + } else { + // TODO: sprite atlas. + commands.entity(entity).insert(UiImage { + image: preview, + ..Default::default() + }); + } } } diff --git a/crates/bevy_editor_launcher/assets/chair.glb b/crates/bevy_editor_launcher/assets/chair.glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/cube.glb b/crates/bevy_editor_launcher/assets/cube.glb new file mode 100644 index 0000000000000000000000000000000000000000..cf6e3499344f26934820c663b8f5cb71bf12383e GIT binary patch literal 1936 zcmb7EZBH6O5FTGzt!=fnZ(qrNzEU_);69Wp)s$Ab28b~+rXH~1CC8oFTWk#>;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV Date: Sat, 23 Nov 2024 10:01:25 +0800 Subject: [PATCH 05/10] preview gen --- crates/bevy_asset_preview/src/lib.rs | 12 +- crates/bevy_asset_preview/src/render/mod.rs | 188 ++++++++---------- .../chair - Copy (2).glb} | Bin .../assets/models/chair - Copy (3).glb | Bin 0 -> 16180 bytes .../assets/models/chair - Copy (4).glb | Bin 0 -> 16180 bytes .../assets/models/chair - Copy (5).glb | Bin 0 -> 16180 bytes .../assets/models/chair - Copy (6).glb | Bin 0 -> 16180 bytes .../assets/models/chair - Copy (7).glb | Bin 0 -> 16180 bytes .../assets/models/chair - Copy (8).glb | Bin 0 -> 16180 bytes .../assets/models/chair - Copy (9).glb | Bin 0 -> 16180 bytes .../assets/models/chair - Copy.glb | Bin 0 -> 16180 bytes .../assets/models/chair.glb | Bin 0 -> 16180 bytes .../{cube.glb => models/cube - Copy (2).glb} | Bin .../assets/models/cube - Copy (3).glb | Bin 0 -> 1936 bytes .../assets/models/cube - Copy (4).glb | Bin 0 -> 1936 bytes .../assets/models/cube - Copy (5).glb | Bin 0 -> 1936 bytes .../assets/models/cube - Copy (6).glb | Bin 0 -> 1936 bytes .../assets/models/cube - Copy (7).glb | Bin 0 -> 1936 bytes .../assets/models/cube - Copy (8).glb | Bin 0 -> 1936 bytes .../assets/models/cube - Copy (9).glb | Bin 0 -> 1936 bytes .../assets/models/cube - Copy.glb | Bin 0 -> 1936 bytes .../assets/models/cube.glb | Bin 0 -> 1936 bytes 22 files changed, 93 insertions(+), 107 deletions(-) rename crates/bevy_editor_launcher/assets/{chair.glb => models/chair - Copy (2).glb} (100%) create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (3).glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (4).glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (5).glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (6).glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (7).glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (8).glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (9).glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy.glb create mode 100644 crates/bevy_editor_launcher/assets/models/chair.glb rename crates/bevy_editor_launcher/assets/{cube.glb => models/cube - Copy (2).glb} (100%) create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (3).glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (4).glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (5).glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (6).glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (7).glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (8).glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (9).glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy.glb create mode 100644 crates/bevy_editor_launcher/assets/models/cube.glb diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index 3bdd319a..7fd5ced1 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -1,14 +1,12 @@ use bevy::{ - app::{App, Plugin, Startup, Update}, + app::{App, Last, Plugin, PostUpdate, PreUpdate, Startup, Update}, asset::{AssetPath, AssetServer, Handle}, gltf::GltfAssetLabel, prelude::{Component, Image, Mesh}, scene::Scene, }; -use crate::render::{ - PrerenderedScenes, PreviewRenderLayers, PreviewRendered, PreviewSceneState, PreviewSettings, -}; +use crate::render::{PrerenderedScenes, PreviewRendered, PreviewSceneState, PreviewSettings}; mod render; mod ui; @@ -54,13 +52,13 @@ impl Plugin for AssetPreviewPlugin { ( render::update_queue, render::update_preview_frames_counter, - render::change_render_layers, ui::preview_handler, ), ) + // Add to PostUpdate to avoid flashing + .add_systems(Last, render::change_render_layers) .init_resource::() .init_resource::() - .init_resource::() - .init_resource::(); + .init_resource::(); } } diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index b148527b..45072b52 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -14,7 +14,7 @@ use bevy::{ world, }, gltf::GltfAssetLabel, - log::{error, info, LogPlugin}, + log::{debug, error, info, LogPlugin}, math::{UVec2, Vec3}, pbr::{DirectionalLight, MeshMaterial3d, PbrPlugin, StandardMaterial}, prelude::{ @@ -28,7 +28,7 @@ use bevy::{ pipelined_rendering::PipelinedRenderingPlugin, render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages}, renderer::RenderDevice, - view::RenderLayers, + view::{GpuCulling, RenderLayers}, Extract, ExtractSchedule, RenderApp, RenderPlugin, }, scene::{InstanceId, Scene, SceneInstance, SceneRoot, SceneSpawner}, @@ -44,40 +44,7 @@ use crate::PreviewAsset; pub const BASE_PREVIEW_LAYER: usize = 128; pub const PREVIEW_LAYERS_COUNT: usize = 8; -pub const PREVIEW_RENDER_FRAMES: u32 = 32; - -#[derive(Resource)] -pub struct PreviewRenderLayers { - available: u64, -} - -impl Default for PreviewRenderLayers { - fn default() -> Self { - Self { available: !0 } - } -} - -impl PreviewRenderLayers { - pub fn occupy(&mut self) -> Option { - if self.is_full() { - None - } else { - let n = self.available.trailing_zeros() as usize; - self.available &= !(1 << n); - Some(n) - } - } - - pub fn free(&mut self, layer: RenderLayers) { - for b in layer.iter() { - self.available &= !(1 << b); - } - } - - pub fn is_full(&self) -> bool { - self.available.trailing_zeros() == PREVIEW_LAYERS_COUNT as u32 - } -} +pub const PREVIEW_RENDER_FRAMES: u32 = 8; #[derive(Resource)] pub struct PreviewSettings { @@ -100,7 +67,7 @@ fn create_prerender_target(settings: &PreviewSettings) -> Image { depth_or_array_layers: 1, }, TextureDimension::D2, - &[255, 0, 0, 255], + &[0, 0, 0, 0], TextureFormat::Bgra8UnormSrgb, Default::default(), ); @@ -128,45 +95,80 @@ pub struct PreviewRendered { #[derive(Resource)] pub struct PreviewSceneState { + available_layers: u8, cameras: [Entity; PREVIEW_LAYERS_COUNT], - handles: [Handle; PREVIEW_LAYERS_COUNT], - instances: [Option; PREVIEW_LAYERS_COUNT], + lights: [Entity; PREVIEW_LAYERS_COUNT], + scene_handles: [Handle; PREVIEW_LAYERS_COUNT], + scene_instances: [Option; PREVIEW_LAYERS_COUNT], applied_layer: [bool; PREVIEW_LAYERS_COUNT], + render_targets: [Handle; PREVIEW_LAYERS_COUNT], } -impl FromWorld for PreviewSceneState { - fn from_world(world: &mut World) -> Self { - let mut cameras = [Entity::PLACEHOLDER; PREVIEW_LAYERS_COUNT]; +impl Default for PreviewSceneState { + fn default() -> Self { + Self { + available_layers: !0, + cameras: [Entity::PLACEHOLDER; PREVIEW_LAYERS_COUNT], + lights: [Entity::PLACEHOLDER; PREVIEW_LAYERS_COUNT], + scene_handles: Default::default(), + scene_instances: Default::default(), + applied_layer: Default::default(), + render_targets: Default::default(), + } + } +} + +impl PreviewSceneState { + pub fn occupy( + &mut self, + handle: Handle, + instance: InstanceId, + render_target: Handle, + commands: &mut Commands, + ) { + if self.is_full() { + return; + } + + let layer = self.available_layers.trailing_zeros() as usize; + self.available_layers &= !(1 << layer); - for i in 0..PREVIEW_LAYERS_COUNT { - world.spawn(( + self.lights[layer] = commands + .spawn(( DirectionalLight::default(), Transform::IDENTITY.looking_to(Vec3::new(1.0, -1.0, 1.0), Vec3::Y), - RenderLayers::from_layers(&[i + BASE_PREVIEW_LAYER]), - )); + RenderLayers::from_layers(&[layer + BASE_PREVIEW_LAYER]), + )) + .id(); + self.cameras[layer] = commands + .spawn(( + Camera3d::default(), + Camera { + target: RenderTarget::Image(render_target.clone()), + ..Default::default() + }, + Transform::from_translation(Vec3::new(-5.0, 2.0, -5.0)) + .looking_at(Vec3::ZERO, Vec3::Y), + RenderLayers::from_layers(&[layer + BASE_PREVIEW_LAYER]), + PreviewRenderView { layer }, + PreviewRenderedFrames::default(), + )) + .id(); + self.render_targets[layer] = render_target; + self.scene_handles[layer] = handle; + self.scene_instances[layer] = Some(instance); + } - cameras[i] = world - .spawn(( - Camera3d::default(), - Camera { - target: RenderTarget::Image(Handle::default()), - is_active: false, - ..Default::default() - }, - Transform::from_translation(Vec3::new(-5.0, 2.0, -5.0)) - .looking_at(Vec3::ZERO, Vec3::Y), - PreviewRenderView { layer: i }, - RenderLayers::from_layers(&[i + BASE_PREVIEW_LAYER]), - )) - .id(); - } + pub fn free(&mut self, layer: usize, commands: &mut Commands) { + self.available_layers |= 1 << layer; + commands.entity(self.lights[layer]).despawn(); + commands.entity(self.cameras[layer]).despawn(); + self.applied_layer[layer] = false; + self.scene_instances[layer] = None; + } - Self { - cameras, - handles: std::array::from_fn(|_| Handle::default()), - instances: [None; PREVIEW_LAYERS_COUNT], - applied_layer: [false; PREVIEW_LAYERS_COUNT], - } + pub fn is_full(&self) -> bool { + self.available_layers.trailing_zeros() == PREVIEW_LAYERS_COUNT as u32 } } @@ -198,50 +200,36 @@ impl PrerenderedScenes { pub(crate) fn update_queue( mut commands: Commands, mut prerendered: ResMut, - mut render_layers: ResMut, mut scene_spawner: ResMut, mut scene_state: ResMut, - mut camera_query: Query<&mut Camera, With>, settings: Res, mut images: ResMut>, mut preview_rendered: EventReader, ) { - while !render_layers.is_full() { - let Some(handle) = prerendered.queue.iter().nth(0).take().cloned() else { - dbg!(); + while !scene_state.is_full() { + let Some(handle) = prerendered.queue.iter().nth(0).cloned() else { break; }; - dbg!(&handle); + prerendered.queue.remove(&handle); let instance = scene_spawner.spawn(handle.clone()); - let layer = render_layers.occupy().unwrap(); - scene_state.handles[layer] = handle; - scene_state.instances[layer] = Some(instance); - scene_state.applied_layer[layer] = false; - - let camera_entity = scene_state.cameras[layer]; - let mut camera = camera_query.get_mut(camera_entity).unwrap(); - camera.is_active = true; - camera.target = RenderTarget::Image(images.add(create_prerender_target(&settings))); - commands - .entity(camera_entity) - .insert(PreviewRenderedFrames::default()); + let render_target = images.add(create_prerender_target(&settings)); + info!("Generating preview image for {:?}", handle); + scene_state.occupy(handle, instance, render_target, &mut commands); } for finished in preview_rendered.read() { - let mut camera = camera_query - .get_mut(scene_state.cameras[finished.layer]) - .unwrap(); - camera.is_active = false; - let RenderTarget::Image(target) = &camera.target else { - unreachable!() - }; - - render_layers.free(RenderLayers::from_layers(&[finished.layer])); - let handle = scene_state.handles[finished.layer].clone(); - dbg!(&handle); - prerendered.rendering.remove(&handle.id()); - prerendered.rendered.insert(handle.id(), target.clone()); + let scene_handle = scene_state.scene_handles[finished.layer].clone(); + prerendered.rendering.remove(&scene_handle.id()); + let render_target = scene_state.render_targets[finished.layer].clone(); + prerendered + .rendered + .insert(scene_handle.id(), render_target); + info!("Preview image for {:?} generated.", scene_handle); + + let instance = scene_state.scene_instances[finished.layer].unwrap(); + scene_spawner.despawn_instance(instance); + scene_state.free(finished.layer, &mut commands); } } @@ -253,7 +241,7 @@ pub(crate) fn update_preview_frames_counter( scene_spawner: Res, ) { for (entity, mut cnt, view) in &mut counters_query { - if scene_state.instances[view.layer] + if scene_state.scene_instances[view.layer] .is_some_and(|inst| scene_spawner.instance_is_ready(inst)) { cnt.cur_frame += 1; @@ -272,7 +260,7 @@ pub(crate) fn change_render_layers( scene_spawner: Res, ) { for layer in 0..PREVIEW_LAYERS_COUNT { - if let Some(instance) = scene_state.instances[layer] { + if let Some(instance) = scene_state.scene_instances[layer] { if !scene_state.applied_layer[layer] && scene_spawner.instance_is_ready(instance) { scene_state.applied_layer[layer] = true; diff --git a/crates/bevy_editor_launcher/assets/chair.glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (2).glb similarity index 100% rename from crates/bevy_editor_launcher/assets/chair.glb rename to crates/bevy_editor_launcher/assets/models/chair - Copy (2).glb diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (3).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (3).glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 zcmeHO33ydilCHz9A}ES$(C1@u3n6=60?7*?(yWmsw6e4bAwU!ovamIc#&&GSo;J2^ zqiySeTcgGm_bnu%5?p)JvBhP28eGT0wQ<+^|8s9$4ma-wdb%B*`AmIP^`CRA{!?}C zx$j>2J{K&SesUKP$&QQssjJBNX(f|aMa%2!D;uH(tD*}kt1Iiu8*1vJ1uRcN z>LUw~5*f9qvU*-+U1Z#_lE|{`w5+u3yl854S!G>)RZTU5Gt<(et5c)(6(EQfr2D8o zS}w7PsT=AzT=wbW>J&AdupNT0KM&aTm_=;F%yg*MfXAH8&LWt1VjU^4Z%r3HB>G01Iim3>Z;~0ZQyWK^puimX~BQ-jG%&DVG zN~WH4dU~`V6J=Lb&#S6nO4e#yRCxtP^)+=~{d1SjpI=!wqpEVb<*BGyyribOvbtgV z$|dM4CnGaAHCj=#v>H2@70W}tb!b*vPDVyvCfPD`vU9myf;ezA*xI5q#*EIweOVQC zd%yw26yrN%vfyi z*U!w0g^JI}%;J<=01heEu!qv$38(#xoQ&KUPH`j>DIP8|YTRUb?X#y^ughE80v}I+ z3!QlvGrrY{SIn3&jywEetel)rhIK8?CBMce#g|sE3*wXE3pZ5+F)rS5eXn5N#UpZZ zi~L?%T|6o$ccad`_}%M!wd%Z!FWOWQ%)9uq>UF_GDGzkVCzV!wVn?_$4xJMUt@emn1C zzkWOKV!wVn?_$4xJD&`r7wwmQ1sL@w#Hc@*cQNYM{g1mC_3QnLyBPJi`u8R7V$>hZ zyBPHc^U1J2S@0HHGnD^DgGS(s>v2Ug>-S%(K+u_th!(d$BPt_It7O zF7|t|^Dg##vGXqWd$IE__It7OF7|t|^GPu85qoFMZW#3k^DajH!Mux6KktR*aWU%W zy|eQ!M*VS}cQNV@=3R{XgLz`A)~uLyDrRkpS&w4YpqT3_=32bR$@7DFi+z5J$&Ym{Cck3xD<(hcv@ztzHH*p5e63$G`4!VE zCck3xEB5!t@{k{6i^)$ei19ubBL}k2aV5ipj5-{M;Ai-xDUc#&BK5TvsvI zRm^o2b6v&mx?zkl>*4PhpNmd0>(Ln2qnPz5W<82ok7B2u7R+gF9Wdg88WeL~#avf0 z*H!H7e~YvKEx4}xZ`Z=LfL}5B6_Z~v`4y92F+86y%R_$Va1Ys+e{Su5`scZY{CK{2 zhFcixKNl_JS4@7z{c zF?;EN{o3q&7%LBZN`{q_J{e|iT3cBg`S*lzJ%|Zo_D&vhB*V&2-wBTU^)RMW?DN=| zFlIk~J-inQvGUU=!`xr(s}tO+YjK}D!>mPP5@5TQKc5h@Px6za6Kr!?ul5zjSR>#` zhMA*lCBv+tA+j)dUOK~!)%Y+5zvbclo-nU#3_a`Ty2!Q9T_WtP%RLF=U96n`{%c=B zJg)DC@lV43UnBlyxUp47yL{4l#3qbSHcx(N_)q7;-i_lrdObYPv0hW3Fa{j_OICBD zYZ|NG5;z?HTl1avjT-Fj*DstWh3WA#Dp-%z}*Ika}Tw%uaqP6_FfB0H^ z(|e*Ae=exUug~41uWf%4)#I-p)U!7+dsB0wn7vucU%%6O!ZD$>!u!X)RleQ!S?dY$ zbsFQxYD}9UF z--vP8^Sbyv^t_(Pw-wc;^o$Q^-(cg_lYe`xPdvZr+JL9Dw12#`bWJdBuT6>9rko#) zV@(6&DebkvxViZR#Fqx+l=h5x)3#VJ29ATnj@7eH&Npp4)z+(?^UP0apAz&z{+pV| z2V<_E-!wWHv%dD)5y9B2KPMQoziqL!V9b4}OF7mbw-psPZ5!d$)mWsS`%>IgQRwx- zeQztep}DzmhV9cE$C|bk4zT;+jsG0$gFWUxY5WOAGweQkwkhk5|?~QM0CNKN*#$0!c?cW=xqpkwGKi>E%)P1wvKX1&w2H5@8 z@wO4({x=q>#~DIR@A01bp66#Q_pAtg+x^%cn{3C^OP{l2oB=ytlG1L+?X|P*_-EVh zv*Y}x3OmL=+HrI98Fsw6_DVa(nX=>Uu_lZKJ=3?LrWKeki~q%r)${y#^IksB4fD(5 z9)AR9hWurS$ z#q+>?dgk-_U_L$b>6uT@e0t{7GoQ~7^XZvS&wP63(=(r*`Si@EXFh+Am`~4qdgk*v zWIjFf>6uT@e0t{d_l@~{PMJ^7e0t{7GoPOM^vtJcK7TKnPtSZl-^{0H{!#GE=a~8Q z%%^8QpL^yf^5o+@`RK_Wx`G#(VX~EFa%r%%^8P{GDe$J@e_APtST7$9#@i58sE( zr}y^1*5>p5z=N4XFfgGr)NGr^Z9;ZK0Wj4na}sNSN|Hn{xyF6 zYyA4x`1P-``Ft;V^{=t{d@nJdp6kmO?6H8YcbC`qRvUhk?H@efw;Zz$UQhI0#OuYlF7RUG^gEI3GB50R#c90f z`5nQ1h*h~)yVRhks?xxY6dj=V{kD^1fGQ$|~t8Gojt3 zpJYj2*uJvAoF)G%ycJ7qy0^PGZJ>B z#HGI(U`E4^mXR{R9B0PBj*-#QOZJtquw&&U$XFQ%J5EMH#>oWO2~rH1Ad_Gx;ZZ1p zErBhO5s(s@0y{+tAX8)->@ZO|J!BB1b5nnAFG%n^`5W-#nvb0lQ283H@Rq(FvXhf<&e%wbsJ5L(j* zatIjvK>I=t1!G_60g%JMcmVW3$l+i-5ZVuN1Q`244}u&C#)F^-LsGzeFtoopLJpHY zuzgGqNFOlvfcAv+1!GTWFUSF4>;>Hiav&J@f$j_G2gZG&`#}x@<9^WIkb}Y88@j(q zkt3uBY!CCLd^agV` zXm@jzq=5G*=uXI&;N1!R2=bMP`3U;4d<<*gjrl}Af$aj{#e6EC!ghu4YCe1b382{LjNjJaPNTKA=@B3z_<g1idGS z!FUh!UPvn#?}gq6X#?YZ(EA||gYkao1CUK%d;t0&8)^mn zz7F~uIRM;iVb@9%WGxt*pg)JK1LM!3zkpl?#$P~x3Aq}Kzl2^2xdx1vLVpFh7L31w z{u*)}n12nuQWi;9$ux_g1?GAAp)AKUupDRq1=yvqOL6wM!q&sq!k7VHe}y>a;qCG>xd3mP3*;EQT`rLG;m?;S-Y)0M zdGP1SK)hYflXKzEl|gvBoGa(RpCg0ub~#7RhCf?|m?5yM;aAIXc(WfU7vU{`5#I9` z!d?t}vHTQrv0MUsiTpF<5?KSgMt%ZWBbUKmCjSJvOfHALTz(9>T&{q5Q*x}{`^CuZ1*|6EB(EPicAu-sP$uT{Vl?t0` z(o7e8Aq;~ZW-`nmd?yTr9cr>nnVD~H0{KLS%VqLxF?21@~UI~BUbj4-(-A2#2d2(}f-D}?5m{|1Dh BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (4).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (4).glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (5).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (5).glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (6).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (6).glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (7).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (7).glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (8).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (8).glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (9).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (9).glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy.glb b/crates/bevy_editor_launcher/assets/models/chair - Copy.glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/models/chair.glb b/crates/bevy_editor_launcher/assets/models/chair.glb new file mode 100644 index 0000000000000000000000000000000000000000..372565381c52c8fde7d2f06e389977d33d0ab225 GIT binary patch literal 16180 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 BgA4!w literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/cube.glb b/crates/bevy_editor_launcher/assets/models/cube - Copy (2).glb similarity index 100% rename from crates/bevy_editor_launcher/assets/cube.glb rename to crates/bevy_editor_launcher/assets/models/cube - Copy (2).glb diff --git a/crates/bevy_editor_launcher/assets/models/cube - Copy (3).glb b/crates/bevy_editor_launcher/assets/models/cube - Copy (3).glb new file mode 100644 index 0000000000000000000000000000000000000000..cf6e3499344f26934820c663b8f5cb71bf12383e GIT binary patch literal 1936 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 Date: Sat, 23 Nov 2024 10:24:23 +0800 Subject: [PATCH 06/10] revert bevy version --- Cargo.toml | 4 ++-- bevy_editor_panes/bevy_2d_viewport/src/lib.rs | 2 +- bevy_editor_panes/bevy_3d_viewport/src/lib.rs | 4 ++-- bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs | 3 +++ bevy_widgets/bevy_menu_bar/src/lib.rs | 2 +- crates/bevy_asset_preview/src/ui.rs | 4 ++-- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6ba3fef0..7e57d616 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,8 +27,8 @@ unsafe_op_in_unsafe_fn = "warn" unused_qualifications = "warn" [workspace.dependencies] -bevy = { version = "0.15.0-rc.3", features = ["wayland"] } -bevy_derive = { version = "0.15.0-rc.3" } +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "015f2c69ca2a2c009fd04eadada282482deaf469", features = ["wayland"] } +bevy_derive = { git = "https://github.com/bevyengine/bevy.git", rev = "015f2c69ca2a2c009fd04eadada282482deaf469" } thiserror = "1" serde = { version = "1", features = ["derive"] } atomicow = "1.0.0" diff --git a/bevy_editor_panes/bevy_2d_viewport/src/lib.rs b/bevy_editor_panes/bevy_2d_viewport/src/lib.rs index e66c02df..4a80ecfa 100644 --- a/bevy_editor_panes/bevy_2d_viewport/src/lib.rs +++ b/bevy_editor_panes/bevy_2d_viewport/src/lib.rs @@ -104,7 +104,7 @@ fn on_pane_creation( let image_id = commands .spawn(( UiImage { - image: image_handle.clone(), + texture: image_handle.clone(), ..Default::default() }, Node { diff --git a/bevy_editor_panes/bevy_3d_viewport/src/lib.rs b/bevy_editor_panes/bevy_3d_viewport/src/lib.rs index d5e7fb9f..1621957e 100644 --- a/bevy_editor_panes/bevy_3d_viewport/src/lib.rs +++ b/bevy_editor_panes/bevy_3d_viewport/src/lib.rs @@ -106,7 +106,7 @@ fn render_target_picking_passthrough( let new_location = Location { position: event.location.position - node_rect.min, - target: NormalizedRenderTarget::Image(ui_image.image.clone()), + target: NormalizedRenderTarget::Image(ui_image.texture.clone()), }; // Duplicate the event @@ -166,7 +166,7 @@ fn on_pane_creation( commands .spawn(( UiImage { - image: image_handle.clone(), + texture: image_handle.clone(), ..Default::default() }, Node { diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs index 97dad2cc..0646a644 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs @@ -15,6 +15,9 @@ use crate::{io, ui::source_id_to_string, AssetBrowserLocation}; use super::{directory_content::delete_folder, DEFAULT_SOURCE_ID_NAME}; +#[derive(Component)] +pub struct RequestPreview; + pub(crate) fn spawn_source_node<'a>( commands: &'a mut Commands, source_id: &AssetSourceId, diff --git a/bevy_widgets/bevy_menu_bar/src/lib.rs b/bevy_widgets/bevy_menu_bar/src/lib.rs index bbfb02c4..57472aae 100644 --- a/bevy_widgets/bevy_menu_bar/src/lib.rs +++ b/bevy_widgets/bevy_menu_bar/src/lib.rs @@ -69,7 +69,7 @@ fn menu_setup( let logo = commands .spawn(UiImage { - image: asset_server.load("embedded://bevy_menu_bar/assets/logo/bevy_logo.png"), + texture: asset_server.load("embedded://bevy_menu_bar/assets/logo/bevy_logo.png"), ..Default::default() }) .id(); diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs index 45d1465b..1128d119 100644 --- a/crates/bevy_asset_preview/src/ui.rs +++ b/crates/bevy_asset_preview/src/ui.rs @@ -38,11 +38,11 @@ pub fn preview_handler( }; if let Some(mut reuseable) = reuseable_image { - reuseable.image = preview; + reuseable.texture = preview; } else { // TODO: sprite atlas. commands.entity(entity).insert(UiImage { - image: preview, + texture: preview, ..Default::default() }); } From b796b7bf25b6c7f9f533e46d4d7250939d141edc Mon Sep 17 00:00:00 2001 From: 443eb9 <443eb9@gmail.com> Date: Sat, 23 Nov 2024 10:37:01 +0800 Subject: [PATCH 07/10] wip --- .gitignore | 2 + .../bevy_asset_browser/src/ui/nodes.rs | 3 -- crates/bevy_asset_preview/src/lib.rs | 9 ++-- crates/bevy_asset_preview/src/render/mod.rs | 43 +++--------------- crates/bevy_asset_preview/src/ui.rs | 1 - .../assets/models/chair - Copy (2).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy (3).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy (4).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy (5).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy (6).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy (7).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy (8).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy (9).glb | Bin 16180 -> 0 bytes .../assets/models/chair - Copy.glb | Bin 16180 -> 0 bytes .../assets/models/chair.glb | Bin 16180 -> 0 bytes .../assets/models/cube - Copy (2).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy (3).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy (4).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy (5).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy (6).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy (7).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy (8).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy (9).glb | Bin 1936 -> 0 bytes .../assets/models/cube - Copy.glb | Bin 1936 -> 0 bytes .../assets/models/cube.glb | Bin 1936 -> 0 bytes 25 files changed, 14 insertions(+), 44 deletions(-) delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (2).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (3).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (4).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (5).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (6).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (7).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (8).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy (9).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair - Copy.glb delete mode 100644 crates/bevy_editor_launcher/assets/models/chair.glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (2).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (3).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (4).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (5).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (6).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (7).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (8).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy (9).glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube - Copy.glb delete mode 100644 crates/bevy_editor_launcher/assets/models/cube.glb diff --git a/.gitignore b/.gitignore index 65a88e51..78748cdd 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ Cargo.lock # mdbook generated files design-book/book + +crates/bevy_editor_launcher/assets/Bevy Assets diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs index 0646a644..97dad2cc 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs @@ -15,9 +15,6 @@ use crate::{io, ui::source_id_to_string, AssetBrowserLocation}; use super::{directory_content::delete_folder, DEFAULT_SOURCE_ID_NAME}; -#[derive(Component)] -pub struct RequestPreview; - pub(crate) fn spawn_source_node<'a>( commands: &'a mut Commands, source_id: &AssetSourceId, diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index 7fd5ced1..3a9845b3 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -1,8 +1,8 @@ use bevy::{ - app::{App, Last, Plugin, PostUpdate, PreUpdate, Startup, Update}, + app::{App, Last, Plugin, Update}, asset::{AssetPath, AssetServer, Handle}, gltf::GltfAssetLabel, - prelude::{Component, Image, Mesh}, + prelude::{Component, Image}, scene::Scene, }; @@ -30,8 +30,9 @@ impl PreviewAsset { let path = <_ as Into>>::into(path); match path.path().extension() { Some(ext) => match ext.to_str().unwrap() { - "png" => Self::Image(asset_server.load(path)), - "glb" => Self::Scene( + "jpg" | "jpeg" | "png" | "bmp" | "gif" | "ico" | "pnm" | "pam" | "pbm" | "pgm" + | "ppm" | "tga" | "webp" => Self::Image(asset_server.load(path)), + "glb" | "gltf" => Self::Scene( asset_server .load(GltfAssetLabel::Scene(0).from_asset(path.path().to_path_buf())), ), diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index 45072b52..357fdd40 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -1,50 +1,23 @@ -use std::collections::VecDeque; - use bevy::{ - app::{App, First, Main, MainSchedulePlugin, PluginsState, Update}, - asset::{AssetId, AssetPlugin, AssetServer, Assets, Handle}, - core::{FrameCountPlugin, TaskPoolPlugin, TypeRegistrationPlugin}, - core_pipeline::CorePipelinePlugin, - diagnostic::LogDiagnosticsPlugin, - ecs::{ - entity::EntityHashMap, - event::{event_update_condition, event_update_system, EventUpdates}, - query::QuerySingleError, - schedule::ScheduleLabel, - world, - }, - gltf::GltfAssetLabel, - log::{debug, error, info, LogPlugin}, + asset::{AssetId, Assets, Handle}, math::{UVec2, Vec3}, - pbr::{DirectionalLight, MeshMaterial3d, PbrPlugin, StandardMaterial}, + pbr::DirectionalLight, prelude::{ - AppTypeRegistry, Camera, Camera3d, Commands, Component, Deref, DerefMut, - DespawnRecursiveExt, Entity, Event, EventReader, EventWriter, FromWorld, Image, - ImagePlugin, IntoSystemConfigs, Mesh, Mesh3d, NonSendMut, PluginGroup, Query, Res, ResMut, - Resource, Transform, With, World, + Camera, Camera3d, Commands, Component, Entity, Event, EventReader, EventWriter, Image, + Query, Res, ResMut, Resource, Transform, }, render::{ camera::RenderTarget, - pipelined_rendering::PipelinedRenderingPlugin, render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages}, - renderer::RenderDevice, - view::{GpuCulling, RenderLayers}, - Extract, ExtractSchedule, RenderApp, RenderPlugin, + view::RenderLayers, }, - scene::{InstanceId, Scene, SceneInstance, SceneRoot, SceneSpawner}, - time::TimePlugin, - ui::{IsDefaultUiCamera, TargetCamera}, + scene::{InstanceId, Scene, SceneSpawner}, utils::{Entry, HashMap, HashSet}, - window::{WindowClosing, WindowCreated, WindowPlugin, WindowResized}, - winit::WinitPlugin, - DefaultPlugins, MinimalPlugins, }; -use crate::PreviewAsset; - pub const BASE_PREVIEW_LAYER: usize = 128; pub const PREVIEW_LAYERS_COUNT: usize = 8; -pub const PREVIEW_RENDER_FRAMES: u32 = 8; +pub const PREVIEW_RENDER_FRAMES: u32 = 16; #[derive(Resource)] pub struct PreviewSettings { @@ -214,7 +187,6 @@ pub(crate) fn update_queue( let instance = scene_spawner.spawn(handle.clone()); let render_target = images.add(create_prerender_target(&settings)); - info!("Generating preview image for {:?}", handle); scene_state.occupy(handle, instance, render_target, &mut commands); } @@ -225,7 +197,6 @@ pub(crate) fn update_queue( prerendered .rendered .insert(scene_handle.id(), render_target); - info!("Preview image for {:?} generated.", scene_handle); let instance = scene_state.scene_instances[finished.layer].unwrap(); scene_spawner.despawn_instance(instance); diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs index 1128d119..a86941e3 100644 --- a/crates/bevy_asset_preview/src/ui.rs +++ b/crates/bevy_asset_preview/src/ui.rs @@ -1,6 +1,5 @@ use bevy::{ asset::AssetServer, - gltf::GltfAssetLabel, prelude::{Commands, Entity, Query, Res, ResMut}, ui::UiImage, }; diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (2).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (2).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (3).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (3).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (4).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (4).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (5).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (5).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (6).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (6).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (7).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (7).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (8).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (8).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy (9).glb b/crates/bevy_editor_launcher/assets/models/chair - Copy (9).glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair - Copy.glb b/crates/bevy_editor_launcher/assets/models/chair - Copy.glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/chair.glb b/crates/bevy_editor_launcher/assets/models/chair.glb deleted file mode 100644 index 372565381c52c8fde7d2f06e389977d33d0ab225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16180 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 BgA4!w diff --git a/crates/bevy_editor_launcher/assets/models/cube - Copy (2).glb b/crates/bevy_editor_launcher/assets/models/cube - Copy (2).glb deleted file mode 100644 index cf6e3499344f26934820c663b8f5cb71bf12383e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1936 zcmb7EZBH6O5FTGzt!=fnZ(qrNzEU_);69Wp)s$Ab28b~+rXH~1CC8oFTWk#>;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV;V1MT zwLh&hd$$TFqFvaXotbBz*_mDFdCmPr0QkKEU@QZCZP>LTbHb2IW(`@7`&>9O5X@rV z&PCt{VXB8Asa=oz9WGMU4|eJ@pU$Q81!k~IE5YkT29C-fftB&|y$)t-JHL}@~nJJki;~|zT z9Vqu7CcKVU~$qcm0mrrjXoCvoL0)8tk;u6$T>eUTe_pa&hGHpNg~{ z^e+OR`?7g;fp@f(HMb4c4hBBH1~X4=zwoBA27ahw7q9x{eb!K4G)NW2j`k`!ynSr% z1UsJdKK6Ox=KqA7x3Xg=Zf93URa*|rjI%c?I|n;;_0VpPKiMqRsMeL_2i)&Te4=Kt zXfQI^-LCrG;LS@%^ynv)%a^wCN^~pkk5yz3jm9TBoq4N3g*-5KArV~I#yTd0bM#cB zCd3VxsJfV^2lZtMV7FSse~@uGo`3GylV4-*+LtFd?%Hb(^3U398_9Wl?Vl&h@p&{4 z>B+s;NzT|~i_{<=4eHmVjI`LMF^UcJ}<4O4R`KEX@CLyOV Date: Sat, 23 Nov 2024 14:22:20 +0800 Subject: [PATCH 08/10] caching --- Cargo.toml | 1 + crates/bevy_asset_preview/Cargo.toml | 4 +- crates/bevy_asset_preview/src/io/mod.rs | 73 +++++++++++ crates/bevy_asset_preview/src/lib.rs | 40 +++++- crates/bevy_asset_preview/src/render/mod.rs | 51 +++++--- .../bevy_asset_preview/src/render/receive.rs | 120 ++++++++++++++++++ crates/bevy_asset_preview/src/ui.rs | 27 +++- 7 files changed, 288 insertions(+), 28 deletions(-) create mode 100644 crates/bevy_asset_preview/src/io/mod.rs create mode 100644 crates/bevy_asset_preview/src/render/receive.rs diff --git a/Cargo.toml b/Cargo.toml index 7e57d616..0db54322 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ unused_qualifications = "warn" [workspace.dependencies] bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "015f2c69ca2a2c009fd04eadada282482deaf469", features = ["wayland"] } bevy_derive = { git = "https://github.com/bevyengine/bevy.git", rev = "015f2c69ca2a2c009fd04eadada282482deaf469" } +crossbeam-channel = "0.5" thiserror = "1" serde = { version = "1", features = ["derive"] } atomicow = "1.0.0" diff --git a/crates/bevy_asset_preview/Cargo.toml b/crates/bevy_asset_preview/Cargo.toml index c2b3ef6f..aeb17027 100644 --- a/crates/bevy_asset_preview/Cargo.toml +++ b/crates/bevy_asset_preview/Cargo.toml @@ -4,4 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -bevy.workspace = true \ No newline at end of file +bevy.workspace = true +crossbeam-channel.workspace = true +image = "0.25" diff --git a/crates/bevy_asset_preview/src/io/mod.rs b/crates/bevy_asset_preview/src/io/mod.rs new file mode 100644 index 00000000..b5b3138d --- /dev/null +++ b/crates/bevy_asset_preview/src/io/mod.rs @@ -0,0 +1,73 @@ +use std::{ + io::{BufWriter, Cursor}, + path::Path, +}; + +use bevy::{ + asset::{ + io::{file::FileAssetWriter, AssetWriter}, + AssetServer, Assets, + }, + prelude::{Image, Res, ResMut}, + render::{renderer::RenderDevice, texture::TextureFormatPixelInfo}, + tasks::IoTaskPool, +}; + +use crate::render::{receive::{MainWorldPreviewImageReceiver, PreviewImageCopies}, RenderedScenePreviews}; + +pub fn save_preview( + mut previews: ResMut, + asset_server: Res, + mut images: ResMut>, + receiver: Res, + mut image_copies: ResMut, +) { + let thread_pool = IoTaskPool::get(); + + while let Ok((id, data)) = receiver.try_recv() { + let image = images.get_mut(id).unwrap(); + let row_bytes = image.width() as usize * image.texture_descriptor.format.pixel_size(); + let aligned_row_bytes = RenderDevice::align_copy_bytes_per_row(row_bytes); + if row_bytes == aligned_row_bytes { + image.data = data; + } else { + image.data = data + .chunks(aligned_row_bytes) + .take(image.height() as usize) + .flat_map(|row| &row[..row_bytes.min(row.len())]) + .cloned() + .collect() + } + + image_copies.remove(&id); + + let Some(scene_handle)=previews.changed.remove(&id) else { + continue; + }; + let Some(path) = asset_server.get_path(scene_handle) else { + continue; + }; + + let image_buffer = match image.clone().try_into_dynamic() { + Ok(img) => img.to_rgba8(), + Err(err) => panic!("Failed to create image buffer {err:?}"), + }; + let image_path = Path::new("cache") + .join("asset_preview") + .join(path.path().with_extension("png")); + + thread_pool + .spawn(async move { + let image_path = image_path.clone(); + let mut writer = BufWriter::new(Cursor::new(Vec::new())); + image_buffer + .write_to(&mut writer, image::ImageFormat::Png) + .unwrap(); + FileAssetWriter::new("", true) + .write_bytes(&image_path, writer.buffer()) + .await + .unwrap(); + }) + .detach(); + } +} diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index 3a9845b3..6502c806 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -2,12 +2,23 @@ use bevy::{ app::{App, Last, Plugin, Update}, asset::{AssetPath, AssetServer, Handle}, gltf::GltfAssetLabel, - prelude::{Component, Image}, + prelude::{Component, Image, IntoSystemConfigs}, + render::{ + extract_resource::ExtractResourcePlugin, graph::CameraDriverLabel, + render_graph::RenderGraph, Render, RenderApp, RenderSet, + }, scene::Scene, }; -use crate::render::{PrerenderedScenes, PreviewRendered, PreviewSceneState, PreviewSettings}; +use crate::render::{ + receive::{ + MainWorldPreviewImageReceiver, PreviewImageCopies, PreviewTextureToBufferLabel, + PreviewTextureToBufferNode, RenderWorldPreviewImageSender, + }, + PreviewRendered, PreviewSceneState, PreviewSettings, RenderedScenePreviews, +}; +mod io; mod render; mod ui; @@ -47,19 +58,36 @@ pub struct AssetPreviewPlugin; impl Plugin for AssetPreviewPlugin { fn build(&self, app: &mut App) { - app.add_event::() + let (s, r) = crossbeam_channel::unbounded(); + + app.add_plugins(ExtractResourcePlugin::::default()) + .add_event::() .add_systems( Update, ( render::update_queue, render::update_preview_frames_counter, ui::preview_handler, + io::save_preview, ), ) - // Add to PostUpdate to avoid flashing .add_systems(Last, render::change_render_layers) - .init_resource::() + .init_resource::() .init_resource::() - .init_resource::(); + .init_resource::() + .init_resource::() + .insert_resource(MainWorldPreviewImageReceiver(r)); + + let render_app = app.sub_app_mut(RenderApp); + render_app + .add_systems( + Render, + render::receive::receive_image_from_buffer.after(RenderSet::Render), + ) + .insert_resource(RenderWorldPreviewImageSender(s)); + + let mut graph = render_app.world_mut().resource_mut::(); + graph.add_node(PreviewTextureToBufferLabel, PreviewTextureToBufferNode); + graph.add_node_edge(CameraDriverLabel, PreviewTextureToBufferLabel); } } diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index 357fdd40..aa814636 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -9,15 +9,21 @@ use bevy::{ render::{ camera::RenderTarget, render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages}, + renderer::RenderDevice, + texture::BevyDefault, view::RenderLayers, }, scene::{InstanceId, Scene, SceneSpawner}, utils::{Entry, HashMap, HashSet}, }; +use crate::render::receive::{PreviewImageCopies, PreviewImageCopy}; + pub const BASE_PREVIEW_LAYER: usize = 128; pub const PREVIEW_LAYERS_COUNT: usize = 8; -pub const PREVIEW_RENDER_FRAMES: u32 = 16; +pub const PREVIEW_RENDER_FRAMES: u32 = 32; + +pub mod receive; #[derive(Resource)] pub struct PreviewSettings { @@ -41,12 +47,14 @@ fn create_prerender_target(settings: &PreviewSettings) -> Image { }, TextureDimension::D2, &[0, 0, 0, 0], - TextureFormat::Bgra8UnormSrgb, + TextureFormat::bevy_default(), Default::default(), ); - image.texture_descriptor.usage |= - TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST | TextureUsages::RENDER_ATTACHMENT; + image.texture_descriptor.usage |= TextureUsages::TEXTURE_BINDING + | TextureUsages::COPY_DST + | TextureUsages::COPY_SRC + | TextureUsages::RENDER_ATTACHMENT; image } @@ -148,21 +156,23 @@ impl PreviewSceneState { /// Scenes that are rendered for preview purpose. This should be inserted into /// main world. #[derive(Resource, Default)] -pub struct PrerenderedScenes { - rendered: HashMap, Handle>, - rendering: HashSet>, - queue: HashSet>, +pub struct RenderedScenePreviews { + pub(crate) changed: HashMap, AssetId>, + pub(crate) available: HashMap, Handle>, + pub(crate) rendering: HashSet>, + pub(crate) queue: HashSet>, } -impl PrerenderedScenes { +impl RenderedScenePreviews { pub fn get_or_schedule(&mut self, handle: Handle) -> Option> { let id = handle.id(); - match self.rendered.entry(id) { + match self.available.entry(id) { Entry::Occupied(e) => Some(e.get().clone()), Entry::Vacant(_) => { if !self.rendering.contains(&id) { self.queue.insert(handle); self.rendering.insert(id); + } else { } None } @@ -172,18 +182,20 @@ impl PrerenderedScenes { pub(crate) fn update_queue( mut commands: Commands, - mut prerendered: ResMut, + mut previews: ResMut, mut scene_spawner: ResMut, mut scene_state: ResMut, settings: Res, mut images: ResMut>, mut preview_rendered: EventReader, + mut image_copies: ResMut, + render_device: Res, ) { while !scene_state.is_full() { - let Some(handle) = prerendered.queue.iter().nth(0).cloned() else { + let Some(handle) = previews.queue.iter().nth(0).cloned() else { break; }; - prerendered.queue.remove(&handle); + previews.queue.remove(&handle); let instance = scene_spawner.spawn(handle.clone()); let render_target = images.add(create_prerender_target(&settings)); @@ -192,11 +204,16 @@ pub(crate) fn update_queue( for finished in preview_rendered.read() { let scene_handle = scene_state.scene_handles[finished.layer].clone(); - prerendered.rendering.remove(&scene_handle.id()); + previews.rendering.remove(&scene_handle.id()); let render_target = scene_state.render_targets[finished.layer].clone(); - prerendered - .rendered - .insert(scene_handle.id(), render_target); + image_copies.insert( + render_target.id(), + PreviewImageCopy::new(settings.resolution.x, settings.resolution.y, &render_device), + ); + previews + .changed + .insert(render_target.id(), scene_handle.id()); + previews.available.insert(scene_handle.id(), render_target); let instance = scene_state.scene_instances[finished.layer].unwrap(); scene_spawner.despawn_instance(instance); diff --git a/crates/bevy_asset_preview/src/render/receive.rs b/crates/bevy_asset_preview/src/render/receive.rs new file mode 100644 index 00000000..1208d2aa --- /dev/null +++ b/crates/bevy_asset_preview/src/render/receive.rs @@ -0,0 +1,120 @@ +use bevy::{ + asset::AssetId, + prelude::{Deref, DerefMut, Image, Res, Resource, World}, + render::{ + extract_resource::ExtractResource, + render_asset::RenderAssets, + render_graph::{Node, NodeRunError, RenderGraphContext, RenderLabel}, + render_resource::{ + Buffer, BufferDescriptor, BufferUsages, Extent3d, ImageCopyBuffer, ImageDataLayout, + Maintain, MapMode, + }, + renderer::{RenderContext, RenderDevice, RenderQueue}, + texture::GpuImage, + }, + scene::Scene, + utils::HashMap, +}; +use crossbeam_channel::{Receiver, Sender}; + +#[derive(Clone, Deref)] +pub struct PreviewImageCopy(Buffer); + +impl PreviewImageCopy { + pub fn new(width: u32, height: u32, render_device: &RenderDevice) -> Self { + let padding_bytes_per_row = RenderDevice::align_copy_bytes_per_row(width as usize * 4); + let buffer = render_device.create_buffer(&BufferDescriptor { + label: None, + size: padding_bytes_per_row as u64 * height as u64, + usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + Self(buffer) + } +} + +#[derive(ExtractResource, Resource, Default, Clone, Deref, DerefMut)] +pub struct PreviewImageCopies(HashMap, PreviewImageCopy>); + +#[derive(Resource, Default, Clone, Deref, DerefMut)] +pub struct TransferredPreviewImages(Vec<(AssetId, AssetId)>); + +#[derive(Resource, Deref)] +pub struct MainWorldPreviewImageReceiver(pub Receiver<(AssetId, Vec)>); + +#[derive(Resource, Deref)] +pub struct RenderWorldPreviewImageSender(pub Sender<(AssetId, Vec)>); + +#[derive(RenderLabel, Debug, Clone, PartialEq, Eq, Hash)] +pub struct PreviewTextureToBufferLabel; + +pub struct PreviewTextureToBufferNode; + +impl Node for PreviewTextureToBufferNode { + fn run<'w>( + &self, + _graph: &mut RenderGraphContext, + render_context: &mut RenderContext<'w>, + world: &'w World, + ) -> Result<(), NodeRunError> { + let image_copies = world.resource::(); + let images = world.resource::>(); + + for (id, buffer) in &**image_copies { + let src = images.get(*id).unwrap(); + let mut encoder = render_context + .render_device() + .create_command_encoder(&Default::default()); + + let block_dimension = src.texture_format.block_dimensions(); + let block_size = src.texture_format.block_copy_size(None).unwrap(); + + let padded_bytes_per_row = RenderDevice::align_copy_bytes_per_row( + (src.size.x as usize / block_dimension.0 as usize) * block_size as usize, + ); + + encoder.copy_texture_to_buffer( + src.texture.as_image_copy(), + ImageCopyBuffer { + buffer: &buffer, + layout: ImageDataLayout { + offset: 0, + bytes_per_row: Some((padded_bytes_per_row as u32).into()), + rows_per_image: None, + }, + }, + Extent3d { + width: src.size.x, + height: src.size.y, + depth_or_array_layers: 1, + }, + ); + + world.resource::().submit([encoder.finish()]); + } + + Ok(()) + } +} + +pub fn receive_image_from_buffer( + image_copies: Res, + render_device: Res, + sender: Res, +) { + for (id, copy) in &**image_copies { + let buffer_slice = copy.slice(..); + + let (s, r) = crossbeam_channel::bounded(1); + buffer_slice.map_async(MapMode::Read, move |r| match r { + Ok(r) => s.send(r).expect("Failed to send map update."), + Err(err) => panic!("Failed to map preview image buffer {:?}", err), + }); + + render_device.poll(Maintain::wait()).panic_on_timeout(); + r.recv().expect("Failed to receive the map_async message"); + + let _ = sender.send((*id, buffer_slice.get_mapped_range().to_vec())); + copy.unmap(); + } +} diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs index a86941e3..fd22449d 100644 --- a/crates/bevy_asset_preview/src/ui.rs +++ b/crates/bevy_asset_preview/src/ui.rs @@ -1,10 +1,16 @@ +use std::path::Path; + use bevy::{ - asset::AssetServer, + asset::{ + io::{file::FileAssetReader, AssetReader}, + AssetServer, + }, prelude::{Commands, Entity, Query, Res, ResMut}, + tasks::block_on, ui::UiImage, }; -use crate::{render::PrerenderedScenes, PreviewAsset}; +use crate::{render::RenderedScenePreviews, PreviewAsset}; const FILE_PLACEHOLDER: &'static str = "embedded://bevy_asset_browser/assets/file_icon.png"; @@ -13,7 +19,7 @@ pub fn preview_handler( mut commands: Commands, mut requests_query: Query<(Entity, &PreviewAsset, Option<&mut UiImage>)>, asset_server: Res, - mut prerendered: ResMut, + mut prerendered: ResMut, ) { for (entity, request, reuseable_image) in &mut requests_query { let preview = match request { @@ -22,7 +28,20 @@ pub fn preview_handler( handle.clone() } PreviewAsset::Scene(handle) => { - if let Some(handle) = prerendered.get_or_schedule(handle.clone()) { + let path = asset_server.get_path(handle).map(|p| { + Path::new("cache") + .join("asset_preview") + .join(p.path().with_extension("png")) + }); + let reader = FileAssetReader::new("cache"); + dbg!(&handle, handle.id()); + + if path + .as_ref() + .is_some_and(|p| block_on(reader.read(p)).is_ok()) + { + asset_server.load(path.unwrap()) + } else if let Some(handle) = prerendered.get_or_schedule(handle.clone()) { commands.entity(entity).remove::(); handle } else { From d182e7156c1fcedefac7d05ce29797da94456a3f Mon Sep 17 00:00:00 2001 From: 443eb9 <443eb9@gmail.com> Date: Sat, 23 Nov 2024 15:04:53 +0800 Subject: [PATCH 09/10] png encoding breaks sometimes? --- .../src/ui/directory_content.rs | 3 +- .../bevy_asset_browser/src/ui/nodes.rs | 3 +- crates/bevy_asset_preview/src/io/mod.rs | 23 ++++---- crates/bevy_asset_preview/src/lib.rs | 32 ++-------- crates/bevy_asset_preview/src/render/mod.rs | 55 ++++++++++++++---- crates/bevy_asset_preview/src/ui.rs | 43 ++++++++------ .../Bevy Assets/models/AlienCake/alien.jpeg | Bin 0 -> 2826 bytes .../models/AlienCake/cakeBirthday.jpeg | Bin 0 -> 2784 bytes .../Bevy Assets/models/AlienCake/tile.jpeg | Bin 0 -> 2987 bytes .../models/CornellBox/CornellBox.jpeg | Bin 0 -> 3305 bytes .../Bevy Assets/models/animated/Fox.jpeg | Bin 0 -> 2419 bytes .../models/animated/MorphStressTest.jpeg | Bin 0 -> 5003 bytes .../Bevy Assets/models/sphere/sphere.jpeg | Bin 0 -> 3371 bytes 13 files changed, 88 insertions(+), 71 deletions(-) create mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/alien.jpeg create mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/cakeBirthday.jpeg create mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/tile.jpeg create mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/CornellBox/CornellBox.jpeg create mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/Fox.jpeg create mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/MorphStressTest.jpeg create mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/sphere/sphere.jpeg diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs index e65a05e2..3174290d 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/directory_content.rs @@ -127,8 +127,7 @@ fn populate_directory_content( .set_parent(parent_entity); } Entry::File(name) => { - spawn_file_node(commands, name.clone(), asset_server, location, theme) - .set_parent(parent_entity); + spawn_file_node(commands, name.clone(), location, theme).set_parent(parent_entity); } } } diff --git a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs index 97dad2cc..0779a60b 100644 --- a/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs +++ b/bevy_editor_panes/bevy_asset_browser/src/ui/nodes.rs @@ -153,7 +153,6 @@ pub(crate) fn spawn_folder_node<'a>( pub(crate) fn spawn_file_node<'a>( commands: &'a mut Commands, file_name: String, - asset_server: &Res, location: &Res, theme: &Res, ) -> EntityCommands<'a> { @@ -162,7 +161,7 @@ pub(crate) fn spawn_file_node<'a>( // Icon commands .spawn(( - PreviewAsset::new(location.path.join(&file_name), asset_server), + PreviewAsset(location.path.join(&file_name)), Node { height: Val::Px(50.0), ..default() diff --git a/crates/bevy_asset_preview/src/io/mod.rs b/crates/bevy_asset_preview/src/io/mod.rs index b5b3138d..20a9731d 100644 --- a/crates/bevy_asset_preview/src/io/mod.rs +++ b/crates/bevy_asset_preview/src/io/mod.rs @@ -13,9 +13,12 @@ use bevy::{ tasks::IoTaskPool, }; -use crate::render::{receive::{MainWorldPreviewImageReceiver, PreviewImageCopies}, RenderedScenePreviews}; +use crate::render::{ + receive::{MainWorldPreviewImageReceiver, PreviewImageCopies}, + RenderedScenePreviews, +}; -pub fn save_preview( +pub fn receive_preview( mut previews: ResMut, asset_server: Res, mut images: ResMut>, @@ -41,27 +44,23 @@ pub fn save_preview( image_copies.remove(&id); - let Some(scene_handle)=previews.changed.remove(&id) else { + let Some(scene_handle) = previews.changed.remove(&id) else { continue; }; let Some(path) = asset_server.get_path(scene_handle) else { continue; }; - let image_buffer = match image.clone().try_into_dynamic() { - Ok(img) => img.to_rgba8(), - Err(err) => panic!("Failed to create image buffer {err:?}"), - }; - let image_path = Path::new("cache") - .join("asset_preview") - .join(path.path().with_extension("png")); + let image_buffer = image.clone().try_into_dynamic().unwrap().to_rgb8(); + let image_path = + Path::new("assets/cache/asset_preview").join(path.path().with_extension("jpeg")); thread_pool .spawn(async move { - let image_path = image_path.clone(); + let image_path = image_path; let mut writer = BufWriter::new(Cursor::new(Vec::new())); image_buffer - .write_to(&mut writer, image::ImageFormat::Png) + .write_to(&mut writer, image::ImageFormat::Jpeg) .unwrap(); FileAssetWriter::new("", true) .write_bytes(&image_path, writer.buffer()) diff --git a/crates/bevy_asset_preview/src/lib.rs b/crates/bevy_asset_preview/src/lib.rs index 6502c806..7b06dd7f 100644 --- a/crates/bevy_asset_preview/src/lib.rs +++ b/crates/bevy_asset_preview/src/lib.rs @@ -1,8 +1,10 @@ +use std::path::PathBuf; + use bevy::{ app::{App, Last, Plugin, Update}, asset::{AssetPath, AssetServer, Handle}, gltf::GltfAssetLabel, - prelude::{Component, Image, IntoSystemConfigs}, + prelude::{Component, Deref, Image, IntoSystemConfigs}, render::{ extract_resource::ExtractResourcePlugin, graph::CameraDriverLabel, render_graph::RenderGraph, Render, RenderApp, RenderSet, @@ -29,30 +31,8 @@ mod ui; /// So long as the assets are unchanged, the previews will be cached and will not need to be re-rendered. /// In theory this can be done passively in the background, and the previews will be ready when the user needs them. -#[derive(Component)] -pub enum PreviewAsset { - Image(Handle), - Scene(Handle), - Other, -} - -impl PreviewAsset { - pub fn new<'a>(path: impl Into>, asset_server: &AssetServer) -> Self { - let path = <_ as Into>>::into(path); - match path.path().extension() { - Some(ext) => match ext.to_str().unwrap() { - "jpg" | "jpeg" | "png" | "bmp" | "gif" | "ico" | "pnm" | "pam" | "pbm" | "pgm" - | "ppm" | "tga" | "webp" => Self::Image(asset_server.load(path)), - "glb" | "gltf" => Self::Scene( - asset_server - .load(GltfAssetLabel::Scene(0).from_asset(path.path().to_path_buf())), - ), - _ => Self::Other, - }, - None => Self::Other, - } - } -} +#[derive(Component, Deref)] +pub struct PreviewAsset(pub PathBuf); pub struct AssetPreviewPlugin; @@ -68,7 +48,7 @@ impl Plugin for AssetPreviewPlugin { render::update_queue, render::update_preview_frames_counter, ui::preview_handler, - io::save_preview, + io::receive_preview, ), ) .add_systems(Last, render::change_render_layers) diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index aa814636..f51e3911 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -1,5 +1,11 @@ +use std::path::{Path, PathBuf}; + use bevy::{ - asset::{AssetId, Assets, Handle}, + asset::{ + io::{file::FileAssetReader, AssetReader}, + AssetId, AssetServer, Assets, Handle, + }, + gltf::GltfAssetLabel, math::{UVec2, Vec3}, pbr::DirectionalLight, prelude::{ @@ -14,6 +20,7 @@ use bevy::{ view::RenderLayers, }, scene::{InstanceId, Scene, SceneSpawner}, + tasks::block_on, utils::{Entry, HashMap, HashSet}, }; @@ -157,6 +164,8 @@ impl PreviewSceneState { /// main world. #[derive(Resource, Default)] pub struct RenderedScenePreviews { + pub(crate) cached: HashMap>, + pub(crate) path_to_handle: HashMap>, pub(crate) changed: HashMap, AssetId>, pub(crate) available: HashMap, Handle>, pub(crate) rendering: HashSet>, @@ -164,17 +173,43 @@ pub struct RenderedScenePreviews { } impl RenderedScenePreviews { - pub fn get_or_schedule(&mut self, handle: Handle) -> Option> { - let id = handle.id(); - match self.available.entry(id) { - Entry::Occupied(e) => Some(e.get().clone()), - Entry::Vacant(_) => { - if !self.rendering.contains(&id) { - self.queue.insert(handle); - self.rendering.insert(id); + pub fn get_or_schedule( + &mut self, + path: PathBuf, + asset_server: &AssetServer, + ) -> Option> { + if let Some(cached) = self.cached.get(&path) { + return Some(cached.clone()); + } + + match self.path_to_handle.entry(path.clone()) { + Entry::Occupied(e) => { + let handle = e.get(); + let id = handle.id(); + match self.available.entry(id) { + Entry::Occupied(e) => Some(e.get().clone()), + Entry::Vacant(_) => { + if !self.rendering.contains(&id) { + self.queue.insert(handle.clone()); + self.rendering.insert(id); + } else { + } + None + } + } + } + Entry::Vacant(e) => { + let cached_path = Path::new("cache/asset_preview").join(path.with_extension("jpeg")); + let reader = FileAssetReader::new("assets"); + + if block_on(reader.read(&cached_path)).is_ok() { + let cached = asset_server.load(cached_path); + self.cached.insert(path, cached.clone()); + Some(cached) } else { + e.insert(asset_server.load(GltfAssetLabel::Scene(0).from_asset(path))); + None } - None } } } diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs index fd22449d..1bbad193 100644 --- a/crates/bevy_asset_preview/src/ui.rs +++ b/crates/bevy_asset_preview/src/ui.rs @@ -14,6 +14,12 @@ use crate::{render::RenderedScenePreviews, PreviewAsset}; const FILE_PLACEHOLDER: &'static str = "embedded://bevy_asset_browser/assets/file_icon.png"; +enum PreviewType { + Image, + Scene, + Other, +} + // TODO: handle assets modification pub fn preview_handler( mut commands: Commands, @@ -21,27 +27,26 @@ pub fn preview_handler( asset_server: Res, mut prerendered: ResMut, ) { - for (entity, request, reuseable_image) in &mut requests_query { - let preview = match request { - PreviewAsset::Image(handle) => { + for (entity, preview, reuseable_image) in &mut requests_query { + let ty = match preview.extension() { + Some(ext) => match ext.to_str().unwrap() { + "jpeg" | "jpeg" | "png" | "bmp" | "gif" | "ico" | "pnm" | "pam" | "pbm" | "pgm" + | "ppm" | "tga" | "webp" => PreviewType::Image, + "glb" | "gltf" => PreviewType::Scene, + _ => PreviewType::Other, + }, + None => PreviewType::Other, + }; + + let preview = match ty { + PreviewType::Image => { commands.entity(entity).remove::(); - handle.clone() + asset_server.load(preview.as_path()) } - PreviewAsset::Scene(handle) => { - let path = asset_server.get_path(handle).map(|p| { - Path::new("cache") - .join("asset_preview") - .join(p.path().with_extension("png")) - }); - let reader = FileAssetReader::new("cache"); - dbg!(&handle, handle.id()); - - if path - .as_ref() - .is_some_and(|p| block_on(reader.read(p)).is_ok()) + PreviewType::Scene => { + if let Some(handle) = + prerendered.get_or_schedule((**preview).clone(), &asset_server) { - asset_server.load(path.unwrap()) - } else if let Some(handle) = prerendered.get_or_schedule(handle.clone()) { commands.entity(entity).remove::(); handle } else { @@ -49,7 +54,7 @@ pub fn preview_handler( asset_server.load(FILE_PLACEHOLDER) } } - PreviewAsset::Other => { + PreviewType::Other => { commands.entity(entity).remove::(); asset_server.load(FILE_PLACEHOLDER) } diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/alien.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/alien.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9937d9664f0497806907567b173dfb8e03e6cf0c GIT binary patch literal 2826 zcmex=ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6O*RKV<1tCX?)^26}(>KBtd zekT`;GW=7TdS-E`srrqT#d+Vh2S=Z5`e?13yv*_7QDcvjo@yN{Bmx*6SQ$hZNTAp+ zOgN;Q9MZ%R~LRM zkeV%+qNB@q?{2$gQ#sjV1D%BiG&#{4XloH&%Xb4{%Suwsm=wY3zdHJ?qwlKD+eCpXDP@;O!sNL)%m$9`}7pbqQ=( zV9CJvGS+=j+65AQ&$#;GlHNbQ%R1wexLYj0vn$l8F#fnywOH%Yl+5k2=NC+z_(-~~ zh^_E-&`YPn%~9e`d**~(zIL>7so)uxN`}IN>#SzDo~_C|a@zD;alxFt3h|CKb2*hO zPjz>j2POQ@Q>dGI)6Zr@pvm)Z^Zqjwo2?-+9WjP>ZAeuyuw*G)z#sSF*!ueXg;AZ) z#C1;ZFIjW6!{(F!b@|q)D1k|Ro$Q@8&c)fw{L8a;t2kKAY4AK&`|FBDsikUj&+{`k zp9Fb)I`zrp_S}-RvCI9~>0QYm9O#lD@ literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/cakeBirthday.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/cakeBirthday.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..3d0bf9a64e13d5a48bf04861c7111fdc44b0d2a1 GIT binary patch literal 2784 zcmex=ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6NRsem!kYmR}!13CBPOAVrn zOG47z0v;C$8SY5w>5p@iZ`E$Nl_0_p!05orKs;4;kMV+69}7XU}mBR3ypOB8;!*^Itj?&%5g63g6@swHlB3EQ7~8f7Y)}S7rNp z=iZzpi?_9x%1&E$vb#1>#fL{|_x_1Y(>K3Wi{H{7V*2H8B;U)g2PXFUpWIScx%lSy zoVZJ}g2(>2^c}S^I;wZ}?)7<#E3BuoTRthAe{D{P(wps~o?d~solj;v&mpnIG2OCW z@RgO7#M`@3LY{^mJ7Yece;KG%IPKYl)fySSQ$AkMviU1_^Zst_+>?KL)8AAZ$FC`O z_-A#?{^FPJjQdw-mwyqdmV0Bj@utMB?HyZX6J5%Uv<~sP1g^V!e*NA|slvWv!K*dj drCgoaNECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6O21=uqJ_qHgzr7IrXym7~G z`Hx9P;h$eR8qG=GZN;tMZuR%#-!BEX)>VE^VR?K*FEi#?#H#FEzqZp4V|RV7UFq?Y z`Dr85gTH>oKLd*;ljU!^JEuOV=Z`GX5lj0zXZl}$*}ocw)07s!5}(KR;qAjaC0{!? z_8dBD?|8i4i^-y^d*%7K8trX)Ia@W8zs+QR{!!w1-IbVI7RRs3eEoiSZq;QqiHEyl z{xh7`G${O%Q#W(bvx`TAt6vm<-(|OS*);KK#)rgLTgmR9@0E6OPU>dOfPer-2UZ3V z27*+zd&7c>et-~w!X;1#T%P&pVv57mjYRj&{qipvqT@vtcdT`(7@;`h<-yfN`=NN5U z6un)h?v)MC=eryKR$YAa>hz;@mr$vCCQD!UM}6yyyly(O&PgdKd}i^-Uw&z(j7`{s z*Pd^Rs@gWLcy%d%|K3>-o-0`YSykKa_#^CMPx2ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)?h|ZfrOVZ`hYZQ0*!KDWe{NqU;;BLWot9PE`*3cC6Fn`*IPfOp9HFJ z&|p{wbOVw_j9{nO^zGa7>jJ_}=q~tr>!16 zA%O6vDkua%d?Nhs4)Xs2Pzb{GbHW(J>NkMI08ATc`oZDP5QG--(1bvQ|NAF#C5RyD zXF-lF;`GBp8*C{k*};+_^NH85{nsM+NR9*x^2e^9WapvTfN(vE?Ha`ChuOxk097}` z0)FN7Ywflm@gC7!Hn7T>xz85^y z85Xb~=b1GB?y<99Bv-duo_`pwC-U6BHDOsaKbN z%!uuFZLPm%ZTam%c&g2|SwH5UJ5`x#`f>L^)*EYeAO2?u7ixapS8w&El`G_*#M}*s zFD?IYWM%z=mr?V4pSB2Xl(-kp+yA}YbmPV|@ij)5)p)Lz2j8}QAuXiw$HH#!?+fh4 z^&g%`Z&kU?k#~9fwBOP4ZpUBvGFk3EYxdi(X#2Fu4#nHQcQ~lu_+sB`pmhPBkHF;+ zmE6;CTMQ4*%3tC5*SGYrPJCW`;Z1+-f0eaIZ)|xTQ7On&8$Ihy8()uE=WTy>Cu#Th zIt>g5B$zj>n=1W&e`vrj#N!-{B`Za;n4Yqg)>;@Q%}y0d@W?YmW(a{t(y*lv%l{VUS#-^zbjcOpUKc&*=!)Gx{V z_ANcqs~n@G)$d>!JFz8ct!VN(gC5aEYphmmK%{=;e9ED>W^Mi=!@IX#t>i8#PPdT}7t#`4ux4{*>uIEy8%_-XDX#{c5LvNw!r)hAce(a289k`96tjUp~(6 zH7nTj=fv&rSL@xqjqb*8SDa)MSejPq+3W=2g^`*esiqKSLT;pD#$&lfw$oLl(e zy!RZjO*>{?{dmBBPyC6`zrZQ@apcxJ*Us|Z;%k)7mOt?E*9GNSdoJsL`KI*gT!q2y zVkH62Z?^ni2_Xyk7d*QBHtE=nM!U6Viw<+TNxM7)rLg{c5e$qC2JDHkoT`hgg1lXj z(iSn!1*UzY_MkP4>?@QS4E6WOFL=ch6>DWu^Ss2e|38D{0sCHtJXr0C+tct0c2vn| MV3C^`82{e{02OY*hX4Qo literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/Fox.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/Fox.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ac515505896b18bfd73f0f5ea8186d5f68e60c79 GIT binary patch literal 2419 zcmex=ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6O21)~{Zv@94c4o6Up!2kay E020n1vH$=8 literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/MorphStressTest.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/MorphStressTest.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ccade403dc32dcf6a761725ded53a3a710613b72 GIT binary patch literal 5003 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 literal 0 HcmV?d00001 diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/sphere/sphere.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/sphere/sphere.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..0efe70a96d127a94253273c9d5996a0ee2c1ae58 GIT binary patch literal 3371 zcmeH}X;c&E8pq$sB$*@xLLgx?LJ$z}Se7KRShk2FP%Mj7!COl!7UP146h+i(0xAdv z5mC0H21Nr3*RqLlESnfaOASKB1r!j)fMSAxfg6&W*yY~S4{dDE=_j8#bKW^;-g)Qw z{h$B5OH27rE`Uw|KgPyj&c1E`t-8K=2|Au>RbA(#xQ9s*y0!(tIE28SRB9*-js zDY`@*9ipj$A&D~I%))%W8I4A_cCe){SZqb3*}2*;c5-I1SQfVKo^A{e2PTW5Sp>r4 z@kAY>iLR~*!;)snc;`^H0Sk4W80c+)UjjnGXbcv?;R!nG3AOqF1;H>14P!89w0ibF z^?iUQV+<^v*;vESFOUUX3L`1I7-zMtvV|JfCADU5_$nDsFfukVHM3c0YiGZRwZz5M z&3&ow@)dq7{R0A5hkvqWZA9d{=#5{-Y~pO*62D_-!mh;Kdk!2tl#+TlE&W)|@e{du z`2~e%&X$}zFDxy)P*q)1d%5mPeM9TDw(Fwy8yz?AbocypxA)%t2ZKXThMztgc`g~1 zO}w6*ntmgnnbmM<6#q4T2KybCx*QM+jfT;Ph6_UNQlBsxjj?pb8n8o=FSv#a7)dzF zvh3o@7Q7WROiJDGRTsg?nl)%6)1bX2(+({8FOmHQ_CKx%fCxis8^L7Y4JH~k5P%&J zp!n~H_Y(Xa7xZ*{xK?bXyPQ7%X`kioS4Pb0e|yQEG*y5dE-FCyI+Bq*9oLeR5fE43 ze(7egT#V{d*vU5PyaHKR@*?HMl=^NL45?1mZd zRGS{L!m~`C{^mtPY<1wZd5_PC@T2W@uO|hhEz;iBIpYyAZZYe_OXRIin=cM_N0ctn@y+aMjU_WCw~X}$7k9B%FEu9UsJDam0ilk*%K zj7n{)R50g?8AD^CZC6!*=sQkow`m&iy>oPa2a6a8g2YfEVESM=kR}y9tD&q^!wBgQ zg&EwOy+ZqJfBN>U%z-)3FX!Ind+6mS|9LTW=ffYxZjGw!_TzFHXQ_1k`kBMG1swuX zX&iZ3X=`b-dGgV=g?vL6I1WPS0#wpBg&>3jMXp)S>G!oll?#iJTJZJvmn1@e8Af?( zEee0%xIcd4bld0M zT@Zc3c&z3WZ;{VliTWk_F?^!f`K_q&YGw69;3UB&z9O_})su%kuz3)7VSJGyscCxK zeo7m+=8thSs8L-@;F7W2r72NHuS+uY2TmZ_@{BAI-|JL>QN-QlpWkR^WQz~@!z`k@ zn!iX>2tE~~atY`1`JlsAt!GQcD6*#4v6k5AV7r^*-a!b4r6v}KoGIEg5V&u@iM(LR zdi;+1zI|0K%Ygr_>s|ilefA2^&BXEQ|F1?2-z_*zX|vvu9m~M4eCU{R7fe+0$X1WX zm9}^I9$wlw2*r1hm{mMVE4x-2=@xm$-E`P#95=~=UMWpvtMbxn2D#f4g02|)v_H#i zDxLIH)+b%?AfeX%4|c7SuAP0@PT6u3o0`18b3o1PYH5jPe4(#H~5M*WnFYFOH?z7Br>( z7{@Fkv2U}lJ5x*F!}ZL#wt2e}C~a wrQvtV8t9~TRp8U%goNm05yLq?L~XZ3Z7lUJ8ULNu_C6Oajr|Xb?5(>0U- Date: Sat, 23 Nov 2024 15:24:57 +0800 Subject: [PATCH 10/10] fixed, now uses png --- crates/bevy_asset_preview/src/io/mod.rs | 39 ++++++++++++++---- crates/bevy_asset_preview/src/render/mod.rs | 2 +- crates/bevy_asset_preview/src/ui.rs | 4 +- .../Bevy Assets/models/AlienCake/alien.jpeg | Bin 2826 -> 0 bytes .../models/AlienCake/cakeBirthday.jpeg | Bin 2784 -> 0 bytes .../Bevy Assets/models/AlienCake/tile.jpeg | Bin 2987 -> 0 bytes .../models/CornellBox/CornellBox.jpeg | Bin 3305 -> 0 bytes .../Bevy Assets/models/animated/Fox.jpeg | Bin 2419 -> 0 bytes .../models/animated/MorphStressTest.jpeg | Bin 5003 -> 0 bytes .../Bevy Assets/models/sphere/sphere.jpeg | Bin 3371 -> 0 bytes 10 files changed, 33 insertions(+), 12 deletions(-) delete mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/alien.jpeg delete mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/cakeBirthday.jpeg delete mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/tile.jpeg delete mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/CornellBox/CornellBox.jpeg delete mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/Fox.jpeg delete mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/MorphStressTest.jpeg delete mode 100644 crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/sphere/sphere.jpeg diff --git a/crates/bevy_asset_preview/src/io/mod.rs b/crates/bevy_asset_preview/src/io/mod.rs index 20a9731d..165834c0 100644 --- a/crates/bevy_asset_preview/src/io/mod.rs +++ b/crates/bevy_asset_preview/src/io/mod.rs @@ -1,6 +1,7 @@ use std::{ + env, io::{BufWriter, Cursor}, - path::Path, + path::{Path, PathBuf}, }; use bevy::{ @@ -12,12 +13,25 @@ use bevy::{ render::{renderer::RenderDevice, texture::TextureFormatPixelInfo}, tasks::IoTaskPool, }; +use image::ImageEncoder; use crate::render::{ receive::{MainWorldPreviewImageReceiver, PreviewImageCopies}, RenderedScenePreviews, }; +pub(crate) fn get_base_path() -> PathBuf { + if let Ok(manifest_dir) = env::var("BEVY_ASSET_ROOT") { + PathBuf::from(manifest_dir) + } else if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") { + PathBuf::from(manifest_dir) + } else { + env::current_exe() + .map(|path| path.parent().map(ToOwned::to_owned).unwrap()) + .unwrap() + } +} + pub fn receive_preview( mut previews: ResMut, asset_server: Res, @@ -51,21 +65,28 @@ pub fn receive_preview( continue; }; - let image_buffer = image.clone().try_into_dynamic().unwrap().to_rgb8(); + let image_buffer = image.clone().try_into_dynamic().unwrap().into_rgba8(); let image_path = - Path::new("assets/cache/asset_preview").join(path.path().with_extension("jpeg")); + Path::new("assets/cache/asset_preview").join(path.path().with_extension("png")); thread_pool .spawn(async move { - let image_path = image_path; - let mut writer = BufWriter::new(Cursor::new(Vec::new())); - image_buffer - .write_to(&mut writer, image::ImageFormat::Jpeg) - .unwrap(); + let image_path_full = get_base_path().join(&image_path); FileAssetWriter::new("", true) - .write_bytes(&image_path, writer.buffer()) + .write(&image_path) .await .unwrap(); + image_buffer.save(image_path_full).unwrap(); + + // TODO use the following code once know why it fails sometimes. + // let mut writer = BufWriter::new(Cursor::new(Vec::new())); + // image_buffer + // .write_to(&mut writer, image::ImageFormat::Png) + // .unwrap(); + // FileAssetWriter::new("", true) + // .write_bytes(&image_path, writer.buffer()) + // .await + // .unwrap(); }) .detach(); } diff --git a/crates/bevy_asset_preview/src/render/mod.rs b/crates/bevy_asset_preview/src/render/mod.rs index f51e3911..b2069e66 100644 --- a/crates/bevy_asset_preview/src/render/mod.rs +++ b/crates/bevy_asset_preview/src/render/mod.rs @@ -199,7 +199,7 @@ impl RenderedScenePreviews { } } Entry::Vacant(e) => { - let cached_path = Path::new("cache/asset_preview").join(path.with_extension("jpeg")); + let cached_path = Path::new("cache/asset_preview").join(path.with_extension("png")); let reader = FileAssetReader::new("assets"); if block_on(reader.read(&cached_path)).is_ok() { diff --git a/crates/bevy_asset_preview/src/ui.rs b/crates/bevy_asset_preview/src/ui.rs index 1bbad193..1f0c52ec 100644 --- a/crates/bevy_asset_preview/src/ui.rs +++ b/crates/bevy_asset_preview/src/ui.rs @@ -30,8 +30,8 @@ pub fn preview_handler( for (entity, preview, reuseable_image) in &mut requests_query { let ty = match preview.extension() { Some(ext) => match ext.to_str().unwrap() { - "jpeg" | "jpeg" | "png" | "bmp" | "gif" | "ico" | "pnm" | "pam" | "pbm" | "pgm" - | "ppm" | "tga" | "webp" => PreviewType::Image, + "jpeg" | "png" | "bmp" | "gif" | "ico" | "pnm" | "pam" | "pbm" | "pgm" | "ppm" + | "tga" | "webp" => PreviewType::Image, "glb" | "gltf" => PreviewType::Scene, _ => PreviewType::Other, }, diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/alien.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/alien.jpeg deleted file mode 100644 index 9937d9664f0497806907567b173dfb8e03e6cf0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2826 zcmex=ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6O*RKV<1tCX?)^26}(>KBtd zekT`;GW=7TdS-E`srrqT#d+Vh2S=Z5`e?13yv*_7QDcvjo@yN{Bmx*6SQ$hZNTAp+ zOgN;Q9MZ%R~LRM zkeV%+qNB@q?{2$gQ#sjV1D%BiG&#{4XloH&%Xb4{%Suwsm=wY3zdHJ?qwlKD+eCpXDP@;O!sNL)%m$9`}7pbqQ=( zV9CJvGS+=j+65AQ&$#;GlHNbQ%R1wexLYj0vn$l8F#fnywOH%Yl+5k2=NC+z_(-~~ zh^_E-&`YPn%~9e`d**~(zIL>7so)uxN`}IN>#SzDo~_C|a@zD;alxFt3h|CKb2*hO zPjz>j2POQ@Q>dGI)6Zr@pvm)Z^Zqjwo2?-+9WjP>ZAeuyuw*G)z#sSF*!ueXg;AZ) z#C1;ZFIjW6!{(F!b@|q)D1k|Ro$Q@8&c)fw{L8a;t2kKAY4AK&`|FBDsikUj&+{`k zp9Fb)I`zrp_S}-RvCI9~>0QYm9O#lD@ diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/cakeBirthday.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/AlienCake/cakeBirthday.jpeg deleted file mode 100644 index 3d0bf9a64e13d5a48bf04861c7111fdc44b0d2a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2784 zcmex=ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6NRsem!kYmR}!13CBPOAVrn zOG47z0v;C$8SY5w>5p@iZ`E$Nl_0_p!05orKs;4;kMV+69}7XU}mBR3ypOB8;!*^Itj?&%5g63g6@swHlB3EQ7~8f7Y)}S7rNp z=iZzpi?_9x%1&E$vb#1>#fL{|_x_1Y(>K3Wi{H{7V*2H8B;U)g2PXFUpWIScx%lSy zoVZJ}g2(>2^c}S^I;wZ}?)7<#E3BuoTRthAe{D{P(wps~o?d~solj;v&mpnIG2OCW z@RgO7#M`@3LY{^mJ7Yece;KG%IPKYl)fySSQ$AkMviU1_^Zst_+>?KL)8AAZ$FC`O z_-A#?{^FPJjQdw-mwyqdmV0Bj@utMB?HyZX6J5%Uv<~sP1g^V!e*NA|slvWv!K*dj drCgoaNECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6O21=uqJ_qHgzr7IrXym7~G z`Hx9P;h$eR8qG=GZN;tMZuR%#-!BEX)>VE^VR?K*FEi#?#H#FEzqZp4V|RV7UFq?Y z`Dr85gTH>oKLd*;ljU!^JEuOV=Z`GX5lj0zXZl}$*}ocw)07s!5}(KR;qAjaC0{!? z_8dBD?|8i4i^-y^d*%7K8trX)Ia@W8zs+QR{!!w1-IbVI7RRs3eEoiSZq;QqiHEyl z{xh7`G${O%Q#W(bvx`TAt6vm<-(|OS*);KK#)rgLTgmR9@0E6OPU>dOfPer-2UZ3V z27*+zd&7c>et-~w!X;1#T%P&pVv57mjYRj&{qipvqT@vtcdT`(7@;`h<-yfN`=NN5U z6un)h?v)MC=eryKR$YAa>hz;@mr$vCCQD!UM}6yyyly(O&PgdKd}i^-Uw&z(j7`{s z*Pd^Rs@gWLcy%d%|K3>-o-0`YSykKa_#^CMPx2ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)?h|ZfrOVZ`hYZQ0*!KDWe{NqU;;BLWot9PE`*3cC6Fn`*IPfOp9HFJ z&|p{wbOVw_j9{nO^zGa7>jJ_}=q~tr>!16 zA%O6vDkua%d?Nhs4)Xs2Pzb{GbHW(J>NkMI08ATc`oZDP5QG--(1bvQ|NAF#C5RyD zXF-lF;`GBp8*C{k*};+_^NH85{nsM+NR9*x^2e^9WapvTfN(vE?Ha`ChuOxk097}` z0)FN7Ywflm@gC7!Hn7T>xz85^y z85Xb~=b1GB?y<99Bv-duo_`pwC-U6BHDOsaKbN z%!uuFZLPm%ZTam%c&g2|SwH5UJ5`x#`f>L^)*EYeAO2?u7ixapS8w&El`G_*#M}*s zFD?IYWM%z=mr?V4pSB2Xl(-kp+yA}YbmPV|@ij)5)p)Lz2j8}QAuXiw$HH#!?+fh4 z^&g%`Z&kU?k#~9fwBOP4ZpUBvGFk3EYxdi(X#2Fu4#nHQcQ~lu_+sB`pmhPBkHF;+ zmE6;CTMQ4*%3tC5*SGYrPJCW`;Z1+-f0eaIZ)|xTQ7On&8$Ihy8()uE=WTy>Cu#Th zIt>g5B$zj>n=1W&e`vrj#N!-{B`Za;n4Yqg)>;@Q%}y0d@W?YmW(a{t(y*lv%l{VUS#-^zbjcOpUKc&*=!)Gx{V z_ANcqs~n@G)$d>!JFz8ct!VN(gC5aEYphmmK%{=;e9ED>W^Mi=!@IX#t>i8#PPdT}7t#`4ux4{*>uIEy8%_-XDX#{c5LvNw!r)hAce(a289k`96tjUp~(6 zH7nTj=fv&rSL@xqjqb*8SDa)MSejPq+3W=2g^`*esiqKSLT;pD#$&lfw$oLl(e zy!RZjO*>{?{dmBBPyC6`zrZQ@apcxJ*Us|Z;%k)7mOt?E*9GNSdoJsL`KI*gT!q2y zVkH62Z?^ni2_Xyk7d*QBHtE=nM!U6Viw<+TNxM7)rLg{c5e$qC2JDHkoT`hgg1lXj z(iSn!1*UzY_MkP4>?@QS4E6WOFL=ch6>DWu^Ss2e|38D{0sCHtJXr0C+tct0c2vn| MV3C^`82{e{02OY*hX4Qo diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/Fox.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/Fox.jpeg deleted file mode 100644 index ac515505896b18bfd73f0f5ea8186d5f68e60c79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2419 zcmex=ECr+Nabot8F zYu9hwy!G(W<0ns_J%91?)yGetzkL1n{m0K=Ab){E90njBL-Q9fIvAN)SeRMZLH=T7 zDhFa_K^9g;LpCADK=#B!VI`wR4iTq`3pXC*R5lL!AevNkkxNX)03>pjzm>Nc@(I6O21)~{Zv@94c4o6Up!2kay E020n1vH$=8 diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/MorphStressTest.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/animated/MorphStressTest.jpeg deleted file mode 100644 index ccade403dc32dcf6a761725ded53a3a710613b72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5003 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 diff --git a/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/sphere/sphere.jpeg b/crates/bevy_editor_launcher/assets/cache/asset_preview/Bevy Assets/models/sphere/sphere.jpeg deleted file mode 100644 index 0efe70a96d127a94253273c9d5996a0ee2c1ae58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3371 zcmeH}X;c&E8pq$sB$*@xLLgx?LJ$z}Se7KRShk2FP%Mj7!COl!7UP146h+i(0xAdv z5mC0H21Nr3*RqLlESnfaOASKB1r!j)fMSAxfg6&W*yY~S4{dDE=_j8#bKW^;-g)Qw z{h$B5OH27rE`Uw|KgPyj&c1E`t-8K=2|Au>RbA(#xQ9s*y0!(tIE28SRB9*-js zDY`@*9ipj$A&D~I%))%W8I4A_cCe){SZqb3*}2*;c5-I1SQfVKo^A{e2PTW5Sp>r4 z@kAY>iLR~*!;)snc;`^H0Sk4W80c+)UjjnGXbcv?;R!nG3AOqF1;H>14P!89w0ibF z^?iUQV+<^v*;vESFOUUX3L`1I7-zMtvV|JfCADU5_$nDsFfukVHM3c0YiGZRwZz5M z&3&ow@)dq7{R0A5hkvqWZA9d{=#5{-Y~pO*62D_-!mh;Kdk!2tl#+TlE&W)|@e{du z`2~e%&X$}zFDxy)P*q)1d%5mPeM9TDw(Fwy8yz?AbocypxA)%t2ZKXThMztgc`g~1 zO}w6*ntmgnnbmM<6#q4T2KybCx*QM+jfT;Ph6_UNQlBsxjj?pb8n8o=FSv#a7)dzF zvh3o@7Q7WROiJDGRTsg?nl)%6)1bX2(+({8FOmHQ_CKx%fCxis8^L7Y4JH~k5P%&J zp!n~H_Y(Xa7xZ*{xK?bXyPQ7%X`kioS4Pb0e|yQEG*y5dE-FCyI+Bq*9oLeR5fE43 ze(7egT#V{d*vU5PyaHKR@*?HMl=^NL45?1mZd zRGS{L!m~`C{^mtPY<1wZd5_PC@T2W@uO|hhEz;iBIpYyAZZYe_OXRIin=cM_N0ctn@y+aMjU_WCw~X}$7k9B%FEu9UsJDam0ilk*%K zj7n{)R50g?8AD^CZC6!*=sQkow`m&iy>oPa2a6a8g2YfEVESM=kR}y9tD&q^!wBgQ zg&EwOy+ZqJfBN>U%z-)3FX!Ind+6mS|9LTW=ffYxZjGw!_TzFHXQ_1k`kBMG1swuX zX&iZ3X=`b-dGgV=g?vL6I1WPS0#wpBg&>3jMXp)S>G!oll?#iJTJZJvmn1@e8Af?( zEee0%xIcd4bld0M zT@Zc3c&z3WZ;{VliTWk_F?^!f`K_q&YGw69;3UB&z9O_})su%kuz3)7VSJGyscCxK zeo7m+=8thSs8L-@;F7W2r72NHuS+uY2TmZ_@{BAI-|JL>QN-QlpWkR^WQz~@!z`k@ zn!iX>2tE~~atY`1`JlsAt!GQcD6*#4v6k5AV7r^*-a!b4r6v}KoGIEg5V&u@iM(LR zdi;+1zI|0K%Ygr_>s|ilefA2^&BXEQ|F1?2-z_*zX|vvu9m~M4eCU{R7fe+0$X1WX zm9}^I9$wlw2*r1hm{mMVE4x-2=@xm$-E`P#95=~=UMWpvtMbxn2D#f4g02|)v_H#i zDxLIH)+b%?AfeX%4|c7SuAP0@PT6u3o0`18b3o1PYH5jPe4(#H~5M*WnFYFOH?z7Br>( z7{@Fkv2U}lJ5x*F!}ZL#wt2e}C~a wrQvtV8t9~TRp8U%goNm05yLq?L~XZ3Z7lUJ8ULNu_C6Oajr|Xb?5(>0U-