Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fuel asset gallery #149

Merged
merged 23 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b247889
First draft of fuel asset gallery
luca-della-vedova Jul 5, 2023
b3b838c
Remove spurious panics, fully support local remote and search fuel
luca-della-vedova Jul 6, 2023
769557f
Improve UX, add tags filter
luca-della-vedova Jul 6, 2023
bfece66
Add async update to fuel cache
luca-della-vedova Jul 6, 2023
b603027
Clear compile warnings
luca-della-vedova Jul 6, 2023
f29bc12
Cleanup and refactors to model logic
luca-della-vedova Jul 7, 2023
314c2bd
Minor cleanups
luca-della-vedova Jul 7, 2023
1832bd5
Merge branch 'main' into luca/fuel_asset_gallery
luca-della-vedova Jul 10, 2023
410ac07
Add private models and API key support
luca-della-vedova Jul 12, 2023
7bb2c3c
Optimize model filtering
luca-della-vedova Jul 12, 2023
19a8c3b
Remove writing to disk in wasm builds
luca-della-vedova Jul 14, 2023
12672a9
Minor format, info message on API key setting
luca-della-vedova Jul 14, 2023
13ca180
Minor cleanups
luca-della-vedova Jul 14, 2023
481126e
Merge branch 'main' into luca/fuel_asset_gallery
luca-della-vedova Aug 18, 2023
62c7b51
Add missing systems to make gallery work in workcell editor mode
luca-della-vedova Aug 18, 2023
789090a
Merge remote-tracking branch 'origin/main' into luca/fuel_asset_gallery
luca-della-vedova Aug 18, 2023
9f0a832
Merge remote-tracking branch 'origin/main' into luca/fuel_asset_gallery
mxgrey Aug 23, 2023
3facbed
Fix merge
mxgrey Aug 23, 2023
e52612c
Leave a note about cargo-check precommit hook
mxgrey Aug 23, 2023
655bcf0
Merge remote-tracking branch 'origin/main' into luca/fuel_asset_gallery
mxgrey Aug 23, 2023
bd22711
Bring back cargo-check precommit hook
mxgrey Aug 23, 2023
91a8256
Address feedback
luca-della-vedova Aug 24, 2023
b13f1f0
Automatically reset poisoned API key
mxgrey Aug 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion rmf_site_editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ tracing = "0.1.37"
tracing-subscriber = "0.3.1"
rfd = "0.11"
urdf-rs = "0.7"
sdformat_rs = { git = "https://github.com/open-rmf/sdf_rust_experimental", rev = "a5daef0"}
sdformat_rs = { git = "https://github.com/open-rmf/sdf_rust_experimental", rev = "f86344f"}
gz-fuel = { git = "https://github.com/luca-della-vedova/gz-fuel/", branch = "first_implementation" }
luca-della-vedova marked this conversation as resolved.
Show resolved Hide resolved
pathdiff = "*"

# only enable the 'dynamic' feature if we're not building for web or windows
Expand Down
3 changes: 3 additions & 0 deletions rmf_site_editor/src/interaction/camera_controls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ pub const HOVERED_OUTLINE_LAYER: u8 = 4;
/// The X-Ray layer is used to show visual cues that need to be rendered
/// above anything that would be obstructing them.
pub const XRAY_RENDER_LAYER: u8 = 5;
/// The Model Preview layer is used by model previews to spawn and render
/// models in the engine without having them being visible to general cameras
pub const MODEL_PREVIEW_LAYER: u8 = 6;

#[derive(Resource)]
struct MouseLocation {
Expand Down
4 changes: 4 additions & 0 deletions rmf_site_editor/src/interaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ pub use light::*;
pub mod mode;
pub use mode::*;

pub mod model_preview;
pub use model_preview::*;

pub mod outline;
pub use outline::*;

Expand Down Expand Up @@ -163,6 +166,7 @@ impl Plugin for InteractionPlugin {
.add_plugin(CategoryVisibilityPlugin::<MeasurementMarker>::default())
.add_plugin(CategoryVisibilityPlugin::<WallMarker>::default())
.add_plugin(CameraControlsPlugin)
.add_plugin(ModelPreviewPlugin)
.add_system_set(
SystemSet::on_update(InteractionState::Enable)
.with_system(make_lift_doormat_gizmo)
Expand Down
90 changes: 90 additions & 0 deletions rmf_site_editor/src/interaction/model_preview.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2023 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

use crate::interaction::MODEL_PREVIEW_LAYER;
use bevy::prelude::*;
use bevy::render::render_resource::{
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
};
use bevy::render::{camera::RenderTarget, primitives::Aabb, view::RenderLayers};
use bevy_egui::{egui::TextureId, EguiContext};

#[derive(Resource)]
pub struct ModelPreviewCamera {
pub camera_entity: Entity,
pub egui_handle: TextureId,
pub model_entity: Entity,
}

pub struct ModelPreviewPlugin;

impl FromWorld for ModelPreviewCamera {
fn from_world(world: &mut World) -> Self {
// camera
let image_size = Extent3d {
width: 320,
height: 240,
depth_or_array_layers: 1,
};
let mut preview_image = Image {
texture_descriptor: TextureDescriptor {
label: None,
size: image_size,
dimension: TextureDimension::D2,
format: TextureFormat::Bgra8UnormSrgb,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
},
..default()
};
preview_image.resize(image_size);
let mut images = world.get_resource_mut::<Assets<Image>>().unwrap();
let preview_image = images.add(preview_image);
let mut egui_context = world.get_resource_mut::<EguiContext>().unwrap();
// Attach the bevy image to the egui image
let egui_handle = egui_context.add_image(preview_image.clone());
let camera_entity = world
.spawn(Camera3dBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Z),
camera: Camera {
target: RenderTarget::Image(preview_image),
..default()
},
..default()
})
.insert(RenderLayers::from_layers(&[MODEL_PREVIEW_LAYER]))
.id();
let model_entity = world
.spawn(RenderLayers::from_layers(&[MODEL_PREVIEW_LAYER]))
.id();

Self {
camera_entity,
egui_handle,
model_entity,
}
}
}

impl Plugin for ModelPreviewPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<ModelPreviewCamera>();
}
}
108 changes: 108 additions & 0 deletions rmf_site_editor/src/site/fuel_cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2023 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

use crate::site::{AssetSource, ModelMarker, ModelSceneRoot, TentativeModelFormat};
use crate::site_asset_io::FUEL_API_KEY;
use crate::widgets::AssetGalleryStatus;
use bevy::prelude::*;
use bevy::tasks::IoTaskPool;
use crossbeam_channel::{Receiver, Sender};
use gz_fuel::{FuelClient as GzFuelClient, FuelModel};

#[derive(Resource, Clone, Default, Deref, DerefMut)]
pub struct FuelClient(GzFuelClient);

/// Event used to request an update to the fuel cache
pub struct UpdateFuelCache;

#[derive(Deref, DerefMut)]
pub struct FuelCacheUpdated(Option<Vec<FuelModel>>);

/// Event used to set the fuel API key from the UI. Will also trigger a reload for failed assets
#[derive(Deref, DerefMut)]
pub struct SetFuelApiKey(pub String);

/// Using channels instead of events to allow usage in wasm since, unlike event writers, they can
/// be cloned and moved into async functions therefore don't have lifetime issues
#[derive(Debug, Resource)]
pub struct UpdateFuelCacheChannels {
pub sender: Sender<FuelCacheUpdated>,
pub receiver: Receiver<FuelCacheUpdated>,
}

impl Default for UpdateFuelCacheChannels {
fn default() -> Self {
let (sender, receiver) = crossbeam_channel::unbounded();
Self { sender, receiver }
}
}

pub fn handle_update_fuel_cache_requests(
mut events: EventReader<UpdateFuelCache>,
mut gallery_status: ResMut<AssetGalleryStatus>,
fuel_client: Res<FuelClient>,
channels: Res<UpdateFuelCacheChannels>,
) {
if events.iter().last().is_some() {
info!("Updating fuel cache, this might take a few minutes");
gallery_status.fetching_cache = true;
let mut fuel_client = fuel_client.clone();
let sender = channels.sender.clone();
IoTaskPool::get()
.spawn(async move {
// Only write to cache in non wasm, no file system in web
#[cfg(target_arch = "wasm32")]
let write_to_disk = false;
#[cfg(not(target_arch = "wasm32"))]
let write_to_disk = true;
// Send client if update was successful
let res = fuel_client.update_cache(write_to_disk).await;
sender
.send(FuelCacheUpdated(res))
.expect("Failed sending fuel cache update event");
})
.detach();
}
}

pub fn read_update_fuel_cache_results(
channels: Res<UpdateFuelCacheChannels>,
mut fuel_client: ResMut<FuelClient>,
mut gallery_status: ResMut<AssetGalleryStatus>,
) {
if let Ok(result) = channels.receiver.try_recv() {
match result.0 {
Some(models) => fuel_client.models = Some(models),
None => error!("Failed updating fuel cache"),
}
gallery_status.fetching_cache = false;
}
}

pub fn reload_failed_models_with_new_api_key(
mut commands: Commands,
mut api_key_events: EventReader<SetFuelApiKey>,
failed_models: Query<Entity, (With<ModelMarker>, Without<ModelSceneRoot>)>,
) {
if let Some(key) = api_key_events.iter().last() {
info!("New API Key set, attempting to re-download failed models");
*FUEL_API_KEY.lock().unwrap() = Some((**key).clone());
for e in &failed_models {
commands.entity(e).insert(TentativeModelFormat::default());
}
}
}
12 changes: 12 additions & 0 deletions rmf_site_editor/src/site/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ pub use fiducial::*;
pub mod floor;
pub use floor::*;

pub mod fuel_cache;
pub use fuel_cache::*;

pub mod group;
pub use group::*;

Expand Down Expand Up @@ -154,9 +157,11 @@ impl Plugin for SitePlugin {
.add_state_to_stage(SiteUpdateStage::AssignOrphans, SiteState::Off)
.add_state_to_stage(CoreStage::PostUpdate, SiteState::Off)
.insert_resource(ClearColor(Color::rgb(0., 0., 0.)))
.init_resource::<FuelClient>()
.init_resource::<SiteAssets>()
.init_resource::<CurrentLevel>()
.init_resource::<PhysicalLightToggle>()
.init_resource::<UpdateFuelCacheChannels>()
.init_resource::<ModelTrashcan>()
.add_event::<LoadSite>()
.add_event::<ImportNavGraphs>()
Expand All @@ -167,6 +172,8 @@ impl Plugin for SitePlugin {
.add_event::<ExportLights>()
.add_event::<ConsiderAssociatedGraph>()
.add_event::<ConsiderLocationTag>()
.add_event::<UpdateFuelCache>()
.add_event::<SetFuelApiKey>()
.add_event::<MergeGroups>()
.add_plugin(ChangePlugin::<AssociatedGraphs<Entity>>::default())
.add_plugin(RecallPlugin::<RecallAssociatedGraphs<Entity>>::default())
Expand Down Expand Up @@ -308,6 +315,7 @@ impl Plugin for SitePlugin {
.with_system(add_measurement_visuals)
.with_system(update_changed_measurement)
.with_system(update_measurement_for_moved_anchors)
.with_system(handle_model_loaded_events)
.with_system(update_constraint_for_moved_anchors)
.with_system(update_constraint_for_changed_labels)
.with_system(update_changed_constraint)
Expand All @@ -317,12 +325,16 @@ impl Plugin for SitePlugin {
.with_system(handle_new_sdf_roots)
.with_system(update_model_scales)
.with_system(make_models_selectable)
.with_system(propagate_model_render_layers)
.with_system(handle_new_mesh_primitives)
.with_system(add_drawing_visuals)
.with_system(handle_loaded_drawing)
.with_system(update_drawing_rank)
.with_system(add_physical_camera_visuals)
.with_system(add_wall_visual)
.with_system(handle_update_fuel_cache_requests)
.with_system(read_update_fuel_cache_results)
.with_system(reload_failed_models_with_new_api_key)
.with_system(update_walls_for_moved_anchors)
.with_system(update_walls)
.with_system(update_transforms_for_changed_poses)
Expand Down
Loading