Last active
June 11, 2025 16:16
-
-
Save matthewjberger/09f1a715cb251b004592a7dd33ba57a0 to your computer and use it in GitHub Desktop.
Revisions
-
matthewjberger revised this gist
Jun 11, 2025 . 1 changed file with 0 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,6 @@ edition = "2024" [dependencies] mimalloc = "0.1.43" re_crash_handler = { version = "0.22.1", features = ["analytics"] } re_grpc_server = "0.22.1" re_sdk_comms = { version = "0.22.1", features = ["server"] } -
matthewjberger revised this gist
Jun 11, 2025 . 1 changed file with 25 additions and 25 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -66,7 +66,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { cc, ); rerun_app.add_receiver(rx); rerun_app.add_view_class::<SystemIpc>().unwrap(); let stream = rerun::RecordingStreamBuilder::new("streamer").spawn()?; Ok(Box::new(MyApp { rerun_app, stream })) @@ -211,33 +211,33 @@ fn format_arrow(array: &dyn arrow::array::Array) -> String { /// A custom view class for rerun #[derive(Default)] pub struct SystemIpc; impl ViewClass for SystemIpc { fn identifier() -> re_types::ViewClassIdentifier where Self: Sized, { "System IPC".into() } fn display_name(&self) -> &'static str { "System IPC" } fn help(&self, egui_ctx: &egui::Context) -> re_viewer::external::re_ui::Help<'_> { Help::new("System IPC").markdown("This is a custom view class for System IPC.") } fn on_register( &self, system_registry: &mut re_viewer::external::re_viewer_context::ViewSystemRegistrator<'_>, ) -> Result<(), re_viewer::external::re_viewer_context::ViewClassRegistryError> { system_registry.register_visualizer::<SystemIpcSystem>() } fn new_state(&self) -> Box<dyn re_viewer::external::re_viewer_context::ViewState> { Box::<SystemIpcViewState>::default() } fn layout_priority(&self) -> re_viewer::external::re_viewer_context::ViewClassLayoutPriority { @@ -259,32 +259,32 @@ impl ViewClass for HyphenIpc { query: &re_viewer::external::re_viewer_context::ViewQuery<'_>, system_output: re_viewer::external::re_viewer_context::SystemExecutionOutput, ) -> Result<(), re_viewer::external::re_viewer_context::ViewSystemExecutionError> { // let system_outputs = system_output.view_systems.get::<SystemIpcSystem>()?; let state = state.downcast_mut::<SystemIpcViewState>()?; ui.label("System IPC Connection"); if ui.button("Connect").clicked() { let _ = state.ipc_client.connect("127.0.0.1:9000"); } Ok(()) } } /// Our System IPC view's contents #[derive(Default)] pub struct SystemIpcSystem { pub value: u8, } impl IdentifiedViewSystem for SystemIpcSystem { fn identifier() -> ViewSystemIdentifier { "InstanceSystemIpc".into() } } impl VisualizerSystem for SystemIpcSystem { fn visualizer_query_info(&self) -> VisualizerQueryInfo { VisualizerQueryInfo::from_archetype::<SystemIpcArchetype>() } /// Populates the scene part with data from the store. @@ -309,11 +309,11 @@ impl VisualizerSystem for HyphenIpcSystem { // Implements a `ComponentFallbackProvider` trait for the `InstanceColorSystem`. // It is left empty here but could be used to provides fallback values for optional components in case they're missing. re_viewer_context::impl_component_fallback_provider!(SystemIpcSystem => []); struct SystemIpcArchetype; impl re_types::Archetype for SystemIpcArchetype { type Indicator = re_types::GenericIndicatorComponent<Self>; fn indicator() -> re_types::SerializedComponentBatch { @@ -323,11 +323,11 @@ impl re_types::Archetype for HyphenIpcArchetype { } fn name() -> re_types::ArchetypeName { "InstanceSystemIpc".into() } fn display_name() -> &'static str { "System IPC" } fn required_components() -> ::std::borrow::Cow<'static, [ComponentDescriptor]> { @@ -338,19 +338,19 @@ impl re_types::Archetype for HyphenIpcArchetype { /// View state for the custom view. /// /// This state is preserved between frames, but not across Viewer sessions. pub struct SystemIpcViewState { ipc_client: ipc::Client, } impl Default for SystemIpcViewState { fn default() -> Self { Self { ipc_client: ipc::Client::new("explorer", ipc::Settings::default()), } } } impl ViewState for SystemIpcViewState { fn as_any(&self) -> &dyn std::any::Any { self } -
matthewjberger revised this gist
Mar 4, 2025 . 1 changed file with 17 additions and 22 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,8 +7,8 @@ use re_viewer::external::{ re_ui::Help, re_viewer_context::{ self, IdentifiedViewSystem, ViewClass, ViewContext, ViewContextCollection, ViewQuery, ViewSpawnHeuristics, ViewState, ViewStateExt, ViewSystemExecutionError, ViewSystemIdentifier, VisualizerQueryInfo, VisualizerSystem, }, }; @@ -69,19 +69,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { rerun_app.add_view_class::<HyphenIpc>().unwrap(); let stream = rerun::RecordingStreamBuilder::new("streamer").spawn()?; Ok(Box::new(MyApp { rerun_app, stream })) }), )?; @@ -90,7 +78,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { struct MyApp { rerun_app: re_viewer::App, stream: rerun::RecordingStream, } @@ -119,9 +106,7 @@ impl MyApp { ui.add_space(4.0); ui.vertical_centered(|ui| { ui.strong("Custom Right Panel"); if ui.button("Connect").clicked() {} }); ui.separator(); @@ -274,9 +259,12 @@ impl ViewClass for HyphenIpc { query: &re_viewer::external::re_viewer_context::ViewQuery<'_>, system_output: re_viewer::external::re_viewer_context::SystemExecutionOutput, ) -> Result<(), re_viewer::external::re_viewer_context::ViewSystemExecutionError> { // let system_outputs = system_output.view_systems.get::<HyphenIpcSystem>()?; let state = state.downcast_mut::<HyphenIpcViewState>()?; ui.label("Hyphen IPC Connection"); if ui.button("Connect").clicked() { let _ = state.ipc_client.connect("127.0.0.1:9000"); } Ok(()) } @@ -350,9 +338,16 @@ impl re_types::Archetype for HyphenIpcArchetype { /// View state for the custom view. /// /// This state is preserved between frames, but not across Viewer sessions. pub struct HyphenIpcViewState { ipc_client: ipc::Client, } impl Default for HyphenIpcViewState { fn default() -> Self { Self { ipc_client: ipc::Client::new("explorer", ipc::Settings::default()), } } } impl ViewState for HyphenIpcViewState { -
matthewjberger revised this gist
Mar 4, 2025 . 1 changed file with 9 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -44,6 +44,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { let startup_options = re_viewer::StartupOptions { hide_welcome_screen: true, persist_state: false, ..Default::default() }; @@ -68,14 +69,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { rerun_app.add_view_class::<HyphenIpc>().unwrap(); let stream = rerun::RecordingStreamBuilder::new("streamer").spawn()?; // stream.log( // "world/xyz/", // &rerun::Arrows3D::from_vectors( // [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], // // ) // .with_colors([[255, 0, 0], [0, 255, 0], [0, 0, 255]]) // .with_labels(["X", "Y", "Z"]), // )?; Ok(Box::new(MyApp { rerun_app, ipc_client: ipc::Client::new("explorer", ipc::Settings::default()), -
matthewjberger created this gist
Mar 4, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,22 @@ [package] name = "scout" version = "0.1.0" edition = "2024" [dependencies] mimalloc = "0.1.43" ipc = { path = "../controls/crates/ipc" } re_crash_handler = { version = "0.22.1", features = ["analytics"] } re_grpc_server = "0.22.1" re_sdk_comms = { version = "0.22.1", features = ["server"] } re_viewer = { version = "0.22.1", features = ["analytics"] } tokio = { version = "1.14.0", features = [ "macros", "rt-multi-thread", "time", "net", "io-util", "sync", "signal", ] } rerun = "0.22.1" This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,365 @@ //! This example shows how to wrap the Rerun Viewer in your own GUI. use re_viewer::external::{ arrow, eframe, egui, re_chunk_store, re_entity_db, re_log, re_log_types, re_memory, re_renderer, re_types::{self, ComponentDescriptor}, re_ui::Help, re_viewer_context::{ self, IdentifiedViewSystem, ViewClass, ViewContext, ViewContextCollection, ViewQuery, ViewSpawnHeuristics, ViewState, ViewSystemExecutionError, ViewSystemIdentifier, VisualizerQueryInfo, VisualizerSystem, }, }; // By using `re_memory::AccountingAllocator` Rerun can keep track of exactly how much memory it is using, // and prune the data store when it goes above a certain limit. // By using `mimalloc` we get faster allocations. #[global_allocator] static GLOBAL: re_memory::AccountingAllocator<mimalloc::MiMalloc> = re_memory::AccountingAllocator::new(mimalloc::MiMalloc); fn main() -> Result<(), Box<dyn std::error::Error>> { let main_thread_token = re_viewer::MainThreadToken::i_promise_i_am_on_the_main_thread(); // Direct calls using the `log` crate to stderr. Control with `RUST_LOG=debug` etc. re_log::setup_logging(); // Install handlers for panics and crashes that prints to stderr and send // them to Rerun analytics (if the `analytics` feature is on in `Cargo.toml`). re_crash_handler::install_crash_handlers(re_viewer::build_info()); // Listen for TCP connections from Rerun's logging SDKs. // There are other ways of "feeding" the viewer though - all you need is a `re_smart_channel::Receiver`. let rx = re_sdk_comms::serve( "0.0.0.0", re_sdk_comms::DEFAULT_SERVER_PORT, Default::default(), )?; let mut native_options = re_viewer::native::eframe_options(None); native_options.viewport = native_options .viewport .with_app_id("rerun_extend_viewer_ui_example"); let startup_options = re_viewer::StartupOptions { hide_welcome_screen: true, ..Default::default() }; // This is used for analytics, if the `analytics` feature is on in `Cargo.toml` let app_env = re_viewer::AppEnvironment::Custom("My Wrapper".to_owned()); let window_title = "My Customized Viewer"; eframe::run_native( window_title, native_options, Box::new(move |cc| { re_viewer::customize_eframe_and_setup_renderer(cc)?; let mut rerun_app = re_viewer::App::new( main_thread_token, re_viewer::build_info(), &app_env, startup_options, cc, ); rerun_app.add_receiver(rx); rerun_app.add_view_class::<HyphenIpc>().unwrap(); let stream = rerun::RecordingStreamBuilder::new("streamer").spawn()?; stream.log( "world/xyz/", &rerun::Arrows3D::from_vectors( [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], // ) .with_colors([[255, 0, 0], [0, 255, 0], [0, 0, 255]]) .with_labels(["X", "Y", "Z"]), )?; Ok(Box::new(MyApp { rerun_app, ipc_client: ipc::Client::new("explorer", ipc::Settings::default()), stream, })) }), )?; Ok(()) } struct MyApp { rerun_app: re_viewer::App, ipc_client: ipc::Client, stream: rerun::RecordingStream, } impl eframe::App for MyApp { fn save(&mut self, storage: &mut dyn eframe::Storage) { // Store viewer state on disk self.rerun_app.save(storage); } /// Called whenever we need repainting, which could be 60 Hz. fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { ui.label("Top panel"); }); egui::SidePanel::right("my_side_panel") .default_width(200.0) .show(ctx, |ui| { self.ui(ui); }); self.rerun_app.update(ctx, frame); } } impl MyApp { fn ui(&mut self, ui: &mut egui::Ui) { ui.add_space(4.0); ui.vertical_centered(|ui| { ui.strong("Custom Right Panel"); if ui.button("Connect").clicked() { // } }); ui.separator(); if let Some(entity_db) = self.rerun_app.recording_db() { entity_db_ui(ui, entity_db); } else { ui.label("No log database loaded yet."); } } } /// Show the content of the log database. fn entity_db_ui(ui: &mut egui::Ui, entity_db: &re_entity_db::EntityDb) { if let Some(store_info) = entity_db.store_info() { ui.label(format!("Application ID: {}", store_info.application_id)); } // There can be many timelines, but the `log_time` timeline is always there: let timeline = re_log_types::Timeline::log_time(); ui.separator(); ui.strong("Entities:"); egui::ScrollArea::vertical() .auto_shrink([false, true]) .show(ui, |ui| { for entity_path in entity_db.entity_paths() { ui.collapsing(entity_path.to_string(), |ui| { entity_ui(ui, entity_db, timeline, entity_path); }); } }); } fn entity_ui( ui: &mut egui::Ui, entity_db: &re_entity_db::EntityDb, timeline: re_log_types::Timeline, entity_path: &re_log_types::EntityPath, ) { // Each entity can have many components (e.g. position, color, radius, …): if let Some(components) = entity_db .storage_engine() .store() .all_components_on_timeline_sorted(&timeline, entity_path) { for component in components { ui.collapsing(component.to_string(), |ui| { component_ui(ui, entity_db, timeline, entity_path, component); }); } } } fn component_ui( ui: &mut egui::Ui, entity_db: &re_entity_db::EntityDb, timeline: re_log_types::Timeline, entity_path: &re_log_types::EntityPath, component_name: re_types::ComponentName, ) { // You can query the data for any time point, but for now // just show the last value logged for each component: let query = re_chunk_store::LatestAtQuery::latest(timeline); let results = entity_db .storage_engine() .cache() .latest_at(&query, entity_path, [component_name]); if let Some(data) = results.component_batch_raw(&component_name) { egui::ScrollArea::vertical() .auto_shrink([false, true]) .show(ui, |ui| { // Iterate over all the instances (e.g. all the points in the point cloud): let num_instances = data.len(); for i in 0..num_instances { ui.label(format_arrow(&*data.slice(i, 1))); } }); }; } fn format_arrow(array: &dyn arrow::array::Array) -> String { use arrow::util::display::{ArrayFormatter, FormatOptions}; let num_bytes = array.get_buffer_memory_size(); if array.len() == 1 && num_bytes < 256 { // Print small items: let options = FormatOptions::default(); if let Ok(formatter) = ArrayFormatter::try_new(array, &options) { return formatter.value(0).to_string(); } } // Fallback: format!("{num_bytes} bytes") } /// A custom view class for rerun #[derive(Default)] pub struct HyphenIpc; impl ViewClass for HyphenIpc { fn identifier() -> re_types::ViewClassIdentifier where Self: Sized, { "Hyphen IPC".into() } fn display_name(&self) -> &'static str { "Hyphen IPC" } fn help(&self, egui_ctx: &egui::Context) -> re_viewer::external::re_ui::Help<'_> { Help::new("Hyphen IPC").markdown("This is a custom view class for Hyphen IPC.") } fn on_register( &self, system_registry: &mut re_viewer::external::re_viewer_context::ViewSystemRegistrator<'_>, ) -> Result<(), re_viewer::external::re_viewer_context::ViewClassRegistryError> { system_registry.register_visualizer::<HyphenIpcSystem>() } fn new_state(&self) -> Box<dyn re_viewer::external::re_viewer_context::ViewState> { Box::<HyphenIpcViewState>::default() } fn layout_priority(&self) -> re_viewer::external::re_viewer_context::ViewClassLayoutPriority { Default::default() } fn spawn_heuristics( &self, ctx: &re_viewer::external::re_viewer_context::ViewerContext<'_>, ) -> re_viewer::external::re_viewer_context::ViewSpawnHeuristics { ViewSpawnHeuristics::root() } fn ui( &self, ctx: &re_viewer::external::re_viewer_context::ViewerContext<'_>, ui: &mut egui::Ui, state: &mut dyn re_viewer::external::re_viewer_context::ViewState, query: &re_viewer::external::re_viewer_context::ViewQuery<'_>, system_output: re_viewer::external::re_viewer_context::SystemExecutionOutput, ) -> Result<(), re_viewer::external::re_viewer_context::ViewSystemExecutionError> { ui.label("Hyphen IPC Connection"); if ui.button("Connect").clicked() { // TODO: Connect to Hyphen IPC } Ok(()) } } /// Our Hyphen IPC view's contents #[derive(Default)] pub struct HyphenIpcSystem { pub value: u8, } impl IdentifiedViewSystem for HyphenIpcSystem { fn identifier() -> ViewSystemIdentifier { "InstanceHyphenIpc".into() } } impl VisualizerSystem for HyphenIpcSystem { fn visualizer_query_info(&self) -> VisualizerQueryInfo { VisualizerQueryInfo::from_archetype::<HyphenIpcArchetype>() } /// Populates the scene part with data from the store. fn execute( &mut self, ctx: &ViewContext<'_>, query: &ViewQuery<'_>, _context_systems: &ViewContextCollection, ) -> Result<Vec<re_renderer::QueueableDrawData>, ViewSystemExecutionError> { // We're not using `re_renderer` here, so return an empty vector. Ok(Vec::new()) } fn as_any(&self) -> &dyn std::any::Any { self } fn fallback_provider(&self) -> &dyn re_viewer_context::ComponentFallbackProvider { self } } // Implements a `ComponentFallbackProvider` trait for the `InstanceColorSystem`. // It is left empty here but could be used to provides fallback values for optional components in case they're missing. re_viewer_context::impl_component_fallback_provider!(HyphenIpcSystem => []); struct HyphenIpcArchetype; impl re_types::Archetype for HyphenIpcArchetype { type Indicator = re_types::GenericIndicatorComponent<Self>; fn indicator() -> re_types::SerializedComponentBatch { use re_types::ComponentBatch as _; #[allow(clippy::unwrap_used)] Self::Indicator::default().serialized().unwrap() } fn name() -> re_types::ArchetypeName { "InstanceHyphenIpc".into() } fn display_name() -> &'static str { "Hyphen IPC" } fn required_components() -> ::std::borrow::Cow<'static, [ComponentDescriptor]> { vec![].into() } } /// View state for the custom view. /// /// This state is preserved between frames, but not across Viewer sessions. #[derive(Default)] pub struct HyphenIpcViewState { // } impl ViewState for HyphenIpcViewState { fn as_any(&self) -> &dyn std::any::Any { self } fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } }