Brought WebGPU demo into same structure as Glium demo
This commit is contained in:
parent
7295852578
commit
b6a7cae830
7 changed files with 329 additions and 465 deletions
|
@ -8,9 +8,7 @@ Things are structured as follows:
|
||||||
* [implot-glium-demo](implot-glium-demo/) is an example for using `implot-rs` in
|
* [implot-glium-demo](implot-glium-demo/) is an example for using `implot-rs` in
|
||||||
conjunction with a [Glium](https://github.com/glium/glium) backend.
|
conjunction with a [Glium](https://github.com/glium/glium) backend.
|
||||||
* [implot-wgpu-demo](implot-wgpu-demo/) is an example for using `implot-rs` in
|
* [implot-wgpu-demo](implot-wgpu-demo/) is an example for using `implot-rs` in
|
||||||
conjunction with a [WebGPU](https://github.com/gfx-rs/wgpu) backend (work in progress, this
|
conjunction with a [WebGPU](https://github.com/gfx-rs/wgpu) backend
|
||||||
uses wgpu, but does currently not make use of `examples-shared` yet and has not been refactored
|
|
||||||
to look the same as the glium example structurally)
|
|
||||||
|
|
||||||
If you want to just copy-paste code to start with, copy `examples-shared` along with
|
If you want to just copy-paste code to start with, copy `examples-shared` along with
|
||||||
your favourite backend example crate. The glium backend code is largely taken from imgui-rs.
|
your favourite backend example crate. The glium backend code is largely taken from imgui-rs.
|
||||||
|
|
40
implot-examples/implot-glium-demo/src/main.rs
Normal file
40
implot-examples/implot-glium-demo/src/main.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use examples_shared;
|
||||||
|
use imgui::{im_str, Condition, Window};
|
||||||
|
use implot::Context;
|
||||||
|
|
||||||
|
// the actual implot samples are in there TODO(4bb4) move to using examples-shared instead
|
||||||
|
mod support;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let system = support::init(file!());
|
||||||
|
let mut showing_demo = false;
|
||||||
|
let mut showing_rust_demo = true;
|
||||||
|
let plotcontext = Context::create();
|
||||||
|
system.main_loop(move |_, ui| {
|
||||||
|
// The context is moved into the closure after creation so plot_ui is valid.
|
||||||
|
let plot_ui = plotcontext.get_plot_ui();
|
||||||
|
|
||||||
|
if showing_demo {
|
||||||
|
implot::show_demo_window(&mut showing_demo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if showing_rust_demo {
|
||||||
|
examples_shared::show_demos(ui, &plot_ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::new(im_str!("Welcome to the ImPlot-rs demo!"))
|
||||||
|
.size([430.0, 450.0], Condition::FirstUseEver)
|
||||||
|
.build(ui, || {
|
||||||
|
ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo);
|
||||||
|
ui.checkbox(
|
||||||
|
im_str!("Show Rust ImPlot demo windows"),
|
||||||
|
&mut showing_rust_demo,
|
||||||
|
);
|
||||||
|
// TODO(4bb4) ... move windows by default so this is less confusing
|
||||||
|
ui.text_wrapped(im_str!(
|
||||||
|
"Note that the windows are stacked, so move this one out of the way to see\
|
||||||
|
the ones beneath it."
|
||||||
|
));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -19,8 +19,8 @@ pub struct System {
|
||||||
pub event_loop: EventLoop<()>,
|
pub event_loop: EventLoop<()>,
|
||||||
pub display: glium::Display,
|
pub display: glium::Display,
|
||||||
pub imgui: Context,
|
pub imgui: Context,
|
||||||
pub platform: WinitPlatform,
|
|
||||||
pub renderer: Renderer,
|
pub renderer: Renderer,
|
||||||
|
pub platform: WinitPlatform,
|
||||||
pub font_size: f32,
|
pub font_size: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,239 +1,40 @@
|
||||||
use futures::executor::block_on;
|
use examples_shared;
|
||||||
use imgui::*;
|
use imgui::{im_str, Condition, Window};
|
||||||
use imgui_wgpu::RendererConfig;
|
use implot::Context;
|
||||||
use std::time::Instant;
|
|
||||||
use winit::{
|
|
||||||
dpi::LogicalSize,
|
|
||||||
event::{Event, WindowEvent},
|
|
||||||
event_loop::{ControlFlow, EventLoop},
|
|
||||||
window::Window,
|
|
||||||
};
|
|
||||||
|
|
||||||
// the actual implot samples are in there TODO(4bb4) move to using examples-shared instead
|
// the actual implot samples are in there TODO(4bb4) move to using examples-shared instead
|
||||||
mod ui;
|
mod support;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// --- Backend setup ----------------------------------------------------------------
|
let system = support::init(file!());
|
||||||
// Set up window and GPU
|
|
||||||
let event_loop = EventLoop::new();
|
|
||||||
let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
|
|
||||||
|
|
||||||
let (window, size, surface) = {
|
|
||||||
let window = Window::new(&event_loop).unwrap();
|
|
||||||
window.set_inner_size(LogicalSize {
|
|
||||||
width: 1280.0,
|
|
||||||
height: 720.0,
|
|
||||||
});
|
|
||||||
window.set_title(&"implot-wgpu".to_string());
|
|
||||||
let size = window.inner_size();
|
|
||||||
|
|
||||||
let surface = unsafe { instance.create_surface(&window) };
|
|
||||||
|
|
||||||
(window, size, surface)
|
|
||||||
};
|
|
||||||
|
|
||||||
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
|
||||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
||||||
compatible_surface: Some(&surface),
|
|
||||||
}))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let (device, queue) = block_on(adapter.request_device(
|
|
||||||
&wgpu::DeviceDescriptor {
|
|
||||||
features: wgpu::Features::empty(),
|
|
||||||
limits: wgpu::Limits::default(),
|
|
||||||
shader_validation: false,
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Set up swap chain
|
|
||||||
let mut sc_desc = wgpu::SwapChainDescriptor {
|
|
||||||
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
|
||||||
width: size.width,
|
|
||||||
height: size.height,
|
|
||||||
present_mode: wgpu::PresentMode::Mailbox,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
|
||||||
|
|
||||||
// Set up dear imgui
|
|
||||||
let mut imgui = imgui::Context::create();
|
|
||||||
let implot = implot::Context::create();
|
|
||||||
|
|
||||||
let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui);
|
|
||||||
platform.attach_window(
|
|
||||||
imgui.io_mut(),
|
|
||||||
&window,
|
|
||||||
imgui_winit_support::HiDpiMode::Default,
|
|
||||||
);
|
|
||||||
imgui.set_ini_filename(None);
|
|
||||||
|
|
||||||
let mut hidpi_factor = window.scale_factor();
|
|
||||||
|
|
||||||
let font_size = (13.0 * hidpi_factor) as f32;
|
|
||||||
imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;
|
|
||||||
|
|
||||||
imgui.fonts().add_font(&[FontSource::DefaultFontData {
|
|
||||||
config: Some(imgui::FontConfig {
|
|
||||||
oversample_h: 1,
|
|
||||||
pixel_snap_h: true,
|
|
||||||
size_pixels: font_size,
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
}]);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Set up dear imgui wgpu renderer
|
|
||||||
//
|
|
||||||
let mut renderer = RendererConfig::new()
|
|
||||||
.set_texture_format(sc_desc.format)
|
|
||||||
.build(&mut imgui, &device, &queue);
|
|
||||||
|
|
||||||
let mut last_frame = Instant::now();
|
|
||||||
let mut last_cursor = None;
|
|
||||||
|
|
||||||
let mut showing_demo = false;
|
let mut showing_demo = false;
|
||||||
let mut make_fullscreen = false;
|
let mut showing_rust_demo = true;
|
||||||
|
let plotcontext = Context::create();
|
||||||
|
system.main_loop(move |_, ui| {
|
||||||
|
// The context is moved into the closure after creation so plot_ui is valid.
|
||||||
|
let plot_ui = plotcontext.get_plot_ui();
|
||||||
|
|
||||||
// --- Event loop -------------------------------------------------------------------
|
if showing_demo {
|
||||||
event_loop.run(move |event, _, control_flow| {
|
implot::show_demo_window(&mut showing_demo);
|
||||||
*control_flow = ControlFlow::Poll;
|
|
||||||
|
|
||||||
let plot_ui = implot.get_plot_ui();
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::ScaleFactorChanged { scale_factor, .. },
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
hidpi_factor = scale_factor;
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::Resized(size),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
// Recreate the swap chain with the new size
|
|
||||||
sc_desc.width = size.width;
|
|
||||||
sc_desc.height = size.height;
|
|
||||||
swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
|
||||||
}
|
|
||||||
Event::WindowEvent {
|
|
||||||
event: WindowEvent::CloseRequested,
|
|
||||||
..
|
|
||||||
} => *control_flow = ControlFlow::Exit,
|
|
||||||
Event::MainEventsCleared => window.request_redraw(),
|
|
||||||
Event::RedrawEventsCleared => {
|
|
||||||
let now = Instant::now();
|
|
||||||
imgui.io_mut().update_delta_time(now - last_frame);
|
|
||||||
last_frame = now;
|
|
||||||
|
|
||||||
let frame = match swap_chain.get_current_frame() {
|
|
||||||
Ok(frame) => frame,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("dropped frame: {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
platform
|
|
||||||
.prepare_frame(imgui.io_mut(), &window)
|
|
||||||
.expect("Failed to prepare frame");
|
|
||||||
let ui = imgui.frame();
|
|
||||||
|
|
||||||
// --- Actual drawing code ----------------------------------------------
|
|
||||||
{
|
|
||||||
let window = imgui::Window::new(im_str!("Hello implot"));
|
|
||||||
let window = if make_fullscreen {
|
|
||||||
let border = 10.0;
|
|
||||||
window.position([0.0, 0.0], Condition::Always).size(
|
|
||||||
[
|
|
||||||
sc_desc.width as f32 / hidpi_factor as f32 - border,
|
|
||||||
sc_desc.height as f32 / hidpi_factor as f32 - border,
|
|
||||||
],
|
|
||||||
Condition::Always,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
window.size([400.0, 300.0], Condition::FirstUseEver)
|
|
||||||
};
|
|
||||||
|
|
||||||
window.build(&ui, || {
|
|
||||||
ui.text(im_str!("Hello from implot-rs!"));
|
|
||||||
ui.text_wrapped(im_str!(
|
|
||||||
"The headers here demo the line plotting features of the library. \
|
|
||||||
Have a look at the example source code to see how they are implemented.\n\
|
|
||||||
Check out the demo from ImPlot itself first \
|
|
||||||
(by enabling the 'Show demo' checkbox) for instructions \
|
|
||||||
on how to interact with ImPlot plots."
|
|
||||||
));
|
|
||||||
|
|
||||||
ui.checkbox(im_str!("Show demo"), &mut showing_demo);
|
|
||||||
ui.checkbox(
|
|
||||||
im_str!("make the implot window fill the whole outer window"),
|
|
||||||
&mut make_fullscreen,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Show individual examples in collapsed headers
|
|
||||||
if CollapsingHeader::new(im_str!("Basic lineplot")).build(&ui) {
|
|
||||||
ui::show_basic_plot(&ui, &plot_ui);
|
|
||||||
}
|
|
||||||
if CollapsingHeader::new(im_str!("Configurable lineplot")).build(&ui) {
|
|
||||||
ui::show_configurable_plot(&ui, &plot_ui);
|
|
||||||
}
|
|
||||||
if CollapsingHeader::new(im_str!("Querying a plot")).build(&ui) {
|
|
||||||
ui::show_query_features_plot(&ui, &plot_ui);
|
|
||||||
}
|
|
||||||
if CollapsingHeader::new(im_str!("Styling a plot")).build(&ui) {
|
|
||||||
ui::show_style_plot(&ui, &plot_ui);
|
|
||||||
}
|
|
||||||
if CollapsingHeader::new(im_str!("Colormap selection")).build(&ui) {
|
|
||||||
ui::show_colormaps_plot(&ui, &plot_ui);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if showing_demo {
|
|
||||||
implot::show_demo_window(&mut showing_demo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Post-drawing rendering code --------------------------------------
|
|
||||||
let mut encoder: wgpu::CommandEncoder =
|
|
||||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
||||||
|
|
||||||
if last_cursor != Some(ui.mouse_cursor()) {
|
|
||||||
last_cursor = Some(ui.mouse_cursor());
|
|
||||||
platform.prepare_render(&ui, &window);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
||||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
|
||||||
attachment: &frame.output.view,
|
|
||||||
resolve_target: None,
|
|
||||||
ops: wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
|
||||||
r: 0.1,
|
|
||||||
g: 0.4,
|
|
||||||
b: 0.3,
|
|
||||||
a: 1.0,
|
|
||||||
}),
|
|
||||||
store: true,
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
depth_stencil_attachment: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
renderer
|
|
||||||
.render(ui.render(), &queue, &device, &mut rpass)
|
|
||||||
.expect("Rendering failed");
|
|
||||||
|
|
||||||
drop(rpass); // renders to screen on drop, will probaly be changed in wgpu 0.7 or later
|
|
||||||
|
|
||||||
queue.submit(Some(encoder.finish()));
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
platform.handle_event(imgui.io_mut(), &window, &event);
|
if showing_rust_demo {
|
||||||
|
examples_shared::show_demos(ui, &plot_ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::new(im_str!("Welcome to the ImPlot-rs demo!"))
|
||||||
|
.size([430.0, 450.0], Condition::FirstUseEver)
|
||||||
|
.build(ui, || {
|
||||||
|
ui.checkbox(im_str!("Show C++ ImPlot demo window"), &mut showing_demo);
|
||||||
|
ui.checkbox(
|
||||||
|
im_str!("Show Rust ImPlot demo windows"),
|
||||||
|
&mut showing_rust_demo,
|
||||||
|
);
|
||||||
|
// TODO(4bb4) ... move windows by default so this is less confusing
|
||||||
|
ui.text_wrapped(im_str!(
|
||||||
|
"Note that the windows are stacked, so move this one out of the way to see\
|
||||||
|
the ones beneath it."
|
||||||
|
));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
24
implot-examples/implot-wgpu-demo/src/support/clipboard.rs
Normal file
24
implot-examples/implot-wgpu-demo/src/support/clipboard.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Taken directly from imgui-rs examples at
|
||||||
|
//
|
||||||
|
// https://github.com/Gekkio/imgui-rs/tree/master/imgui-examples/examples/support
|
||||||
|
//
|
||||||
|
// Not my code. Originally by Joonas Javanainen and the ImGUI-rs contributors
|
||||||
|
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||||
|
use imgui::{ClipboardBackend, ImStr, ImString};
|
||||||
|
|
||||||
|
pub struct ClipboardSupport(ClipboardContext);
|
||||||
|
|
||||||
|
pub fn init() -> Option<ClipboardSupport> {
|
||||||
|
ClipboardContext::new()
|
||||||
|
.ok()
|
||||||
|
.map(|ctx| ClipboardSupport(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClipboardBackend for ClipboardSupport {
|
||||||
|
fn get(&mut self) -> Option<ImString> {
|
||||||
|
self.0.get_contents().ok().map(|text| text.into())
|
||||||
|
}
|
||||||
|
fn set(&mut self, text: &ImStr) {
|
||||||
|
let _ = self.0.set_contents(text.to_str().to_owned());
|
||||||
|
}
|
||||||
|
}
|
233
implot-examples/implot-wgpu-demo/src/support/mod.rs
Normal file
233
implot-examples/implot-wgpu-demo/src/support/mod.rs
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
use futures::executor::block_on;
|
||||||
|
use imgui::{Context, FontSource, Ui};
|
||||||
|
use imgui_wgpu::{Renderer, RendererConfig};
|
||||||
|
use imgui_winit_support::WinitPlatform;
|
||||||
|
use std::time::Instant;
|
||||||
|
use winit::{
|
||||||
|
dpi::LogicalSize,
|
||||||
|
event::{Event, WindowEvent},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::Window,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct System {
|
||||||
|
pub event_loop: EventLoop<()>,
|
||||||
|
pub imgui: Context,
|
||||||
|
pub renderer: Renderer,
|
||||||
|
pub platform: WinitPlatform,
|
||||||
|
pub font_size: f32,
|
||||||
|
pub hidpi_factor: f64,
|
||||||
|
pub sc_desc: wgpu::SwapChainDescriptor,
|
||||||
|
pub swap_chain: wgpu::SwapChain,
|
||||||
|
pub window: Window,
|
||||||
|
pub device: wgpu::Device,
|
||||||
|
pub queue: wgpu::Queue,
|
||||||
|
pub surface: wgpu::Surface,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(title: &str) -> System {
|
||||||
|
// Set up window and GPU
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
|
||||||
|
|
||||||
|
let (window, size, surface) = {
|
||||||
|
let window = Window::new(&event_loop).unwrap();
|
||||||
|
window.set_inner_size(LogicalSize {
|
||||||
|
width: 1280.0,
|
||||||
|
height: 720.0,
|
||||||
|
});
|
||||||
|
window.set_title(title);
|
||||||
|
let size = window.inner_size();
|
||||||
|
|
||||||
|
let surface = unsafe { instance.create_surface(&window) };
|
||||||
|
|
||||||
|
(window, size, surface)
|
||||||
|
};
|
||||||
|
|
||||||
|
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||||
|
compatible_surface: Some(&surface),
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (device, queue) = block_on(adapter.request_device(
|
||||||
|
&wgpu::DeviceDescriptor {
|
||||||
|
features: wgpu::Features::empty(),
|
||||||
|
limits: wgpu::Limits::default(),
|
||||||
|
shader_validation: false,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Set up swap chain
|
||||||
|
let sc_desc = wgpu::SwapChainDescriptor {
|
||||||
|
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
|
||||||
|
format: wgpu::TextureFormat::Bgra8Unorm,
|
||||||
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
|
present_mode: wgpu::PresentMode::Mailbox,
|
||||||
|
};
|
||||||
|
|
||||||
|
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||||
|
|
||||||
|
// Set up dear imgui
|
||||||
|
let mut imgui = imgui::Context::create();
|
||||||
|
|
||||||
|
let mut platform = imgui_winit_support::WinitPlatform::init(&mut imgui);
|
||||||
|
platform.attach_window(
|
||||||
|
imgui.io_mut(),
|
||||||
|
&window,
|
||||||
|
imgui_winit_support::HiDpiMode::Default,
|
||||||
|
);
|
||||||
|
imgui.set_ini_filename(None);
|
||||||
|
|
||||||
|
let hidpi_factor = window.scale_factor();
|
||||||
|
|
||||||
|
let font_size = (13.0 * hidpi_factor) as f32;
|
||||||
|
imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;
|
||||||
|
|
||||||
|
imgui.fonts().add_font(&[FontSource::DefaultFontData {
|
||||||
|
config: Some(imgui::FontConfig {
|
||||||
|
oversample_h: 1,
|
||||||
|
pixel_snap_h: true,
|
||||||
|
size_pixels: font_size,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
}]);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set up dear imgui wgpu renderer
|
||||||
|
//
|
||||||
|
let renderer = RendererConfig::new()
|
||||||
|
.set_texture_format(sc_desc.format)
|
||||||
|
.build(&mut imgui, &device, &queue);
|
||||||
|
|
||||||
|
System {
|
||||||
|
event_loop,
|
||||||
|
imgui,
|
||||||
|
renderer,
|
||||||
|
platform,
|
||||||
|
font_size,
|
||||||
|
hidpi_factor,
|
||||||
|
sc_desc,
|
||||||
|
swap_chain,
|
||||||
|
window,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
surface,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System {
|
||||||
|
pub fn main_loop<F: FnMut(&mut bool, &mut Ui) + 'static>(self, mut run_ui: F) {
|
||||||
|
let System {
|
||||||
|
event_loop,
|
||||||
|
mut imgui,
|
||||||
|
mut renderer,
|
||||||
|
// Currently not used, but was used pre-refactor
|
||||||
|
// mut hidpi_factor,
|
||||||
|
mut sc_desc,
|
||||||
|
mut platform,
|
||||||
|
window,
|
||||||
|
mut swap_chain,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
surface,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
let mut last_frame = Instant::now();
|
||||||
|
let mut last_cursor = None;
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
*control_flow = ControlFlow::Poll;
|
||||||
|
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::ScaleFactorChanged { scale_factor, .. },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
// This
|
||||||
|
let _hidpi_factor = scale_factor;
|
||||||
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::Resized(size),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
// Recreate the swap chain with the new size
|
||||||
|
sc_desc.width = size.width;
|
||||||
|
sc_desc.height = size.height;
|
||||||
|
swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||||
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => *control_flow = ControlFlow::Exit,
|
||||||
|
Event::MainEventsCleared => window.request_redraw(),
|
||||||
|
Event::RedrawEventsCleared => {
|
||||||
|
let now = Instant::now();
|
||||||
|
imgui.io_mut().update_delta_time(now - last_frame);
|
||||||
|
last_frame = now;
|
||||||
|
|
||||||
|
let frame = match swap_chain.get_current_frame() {
|
||||||
|
Ok(frame) => frame,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("dropped frame: {:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
platform
|
||||||
|
.prepare_frame(imgui.io_mut(), &window)
|
||||||
|
.expect("Failed to prepare frame");
|
||||||
|
let mut ui = imgui.frame();
|
||||||
|
|
||||||
|
// --- Actual drawing code ----------------------------------------------
|
||||||
|
let mut run = true;
|
||||||
|
run_ui(&mut run, &mut ui);
|
||||||
|
if !run {
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Post-drawing rendering code --------------------------------------
|
||||||
|
let mut encoder: wgpu::CommandEncoder = device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
|
||||||
|
if last_cursor != Some(ui.mouse_cursor()) {
|
||||||
|
last_cursor = Some(ui.mouse_cursor());
|
||||||
|
platform.prepare_render(&ui, &window);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||||
|
attachment: &frame.output.view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||||
|
// TODO(4bb4) remove hardcoded values here
|
||||||
|
r: 0.1,
|
||||||
|
g: 0.4,
|
||||||
|
b: 0.3,
|
||||||
|
a: 1.0,
|
||||||
|
}),
|
||||||
|
store: true,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
renderer
|
||||||
|
.render(ui.render(), &queue, &device, &mut rpass)
|
||||||
|
.expect("Rendering failed");
|
||||||
|
|
||||||
|
drop(rpass); // renders to screen on drop, will probaly be changed in wgpu 0.7 or later
|
||||||
|
|
||||||
|
queue.submit(Some(encoder.finish()));
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
platform.handle_event(imgui.io_mut(), &window, &event);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,232 +0,0 @@
|
||||||
use imgui::{im_str, Condition, Ui};
|
|
||||||
use implot::{
|
|
||||||
get_plot_limits, get_plot_mouse_position, get_plot_query, is_plot_hovered, is_plot_queried,
|
|
||||||
push_style_color, push_style_var_f32, push_style_var_i32, set_colormap_from_preset,
|
|
||||||
set_colormap_from_vec, AxisFlags, Colormap, ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec4,
|
|
||||||
Marker, Plot, PlotColorElement, PlotFlags, PlotLine, PlotUi, StyleVar, YAxisChoice,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) {
|
|
||||||
ui.text(im_str!(
|
|
||||||
"This header just plots a line with as little code as possible."
|
|
||||||
));
|
|
||||||
let content_width = ui.window_content_region_width();
|
|
||||||
Plot::new("Simple line plot")
|
|
||||||
// The size call could also be omitted, though the defaults don't consider window
|
|
||||||
// width, which is why we're not doing so here.
|
|
||||||
.size(content_width, 300.0)
|
|
||||||
.build(plot_ui, || {
|
|
||||||
// If this is called outside a plot build callback, the program will panic.
|
|
||||||
let x_positions = vec![0.1, 0.9];
|
|
||||||
let y_positions = vec![0.1, 0.9];
|
|
||||||
PlotLine::new("legend label").plot(&x_positions, &y_positions);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_configurable_plot(ui: &Ui, plot_ui: &PlotUi) {
|
|
||||||
ui.text(im_str!(
|
|
||||||
"This header demos what we can configure about plots."
|
|
||||||
));
|
|
||||||
|
|
||||||
// Settings for the plot
|
|
||||||
// - X and Y size in pixels
|
|
||||||
let x_size = 300.0;
|
|
||||||
let y_size = 200.0;
|
|
||||||
// - Strings for the axis labels
|
|
||||||
let x_label = "X label";
|
|
||||||
let y_label = "Y label!";
|
|
||||||
// - Plot limits
|
|
||||||
let x_min = 2.0;
|
|
||||||
let x_max = 3.0;
|
|
||||||
let y_min = 1.0;
|
|
||||||
let y_max = 2.0;
|
|
||||||
// - Plot flags, see the PlotFlags docs for more info
|
|
||||||
let plot_flags = PlotFlags::NONE;
|
|
||||||
// - Axis flags, see the AxisFlags docs for more info. All flags are bitflags-created,
|
|
||||||
// so they support a bunch of convenient operations, see https://docs.rs/bitflags
|
|
||||||
let x_axis_flags = AxisFlags::NONE;
|
|
||||||
let y_axis_flags = AxisFlags::NONE;
|
|
||||||
|
|
||||||
// - Unlabelled X axis ticks
|
|
||||||
let x_ticks = vec![2.2, 2.5, 2.8];
|
|
||||||
|
|
||||||
// - Labelled Y axis ticks
|
|
||||||
let y_ticks = vec![(1.1, "A".to_owned()), (1.4, "B".to_owned())];
|
|
||||||
|
|
||||||
// Axis labels
|
|
||||||
Plot::new("Configured line plot")
|
|
||||||
.size(x_size, y_size)
|
|
||||||
.x_label(&x_label)
|
|
||||||
.y_label(&y_label)
|
|
||||||
.x_limits(
|
|
||||||
&ImPlotRange {
|
|
||||||
Min: x_min,
|
|
||||||
Max: x_max,
|
|
||||||
},
|
|
||||||
// Always means that the limits stay what we force them to here, even if the user
|
|
||||||
// scrolls or drags in the plot with the mouse. FirstUseEver sets the limits the
|
|
||||||
// first time the plot is drawn, but the user can then modify them and the change
|
|
||||||
// will stick.
|
|
||||||
Condition::Always,
|
|
||||||
)
|
|
||||||
.y_limits(
|
|
||||||
&ImPlotRange {
|
|
||||||
Min: y_min,
|
|
||||||
Max: y_max,
|
|
||||||
},
|
|
||||||
YAxisChoice::First,
|
|
||||||
Condition::Always,
|
|
||||||
)
|
|
||||||
.x_ticks(&x_ticks, false)
|
|
||||||
.y_ticks_with_labels(YAxisChoice::First, &y_ticks, false)
|
|
||||||
// If any of these flag setting calls are omitted, the defaults are used.
|
|
||||||
.with_plot_flags(&plot_flags)
|
|
||||||
.with_x_axis_flags(&x_axis_flags)
|
|
||||||
.with_y_axis_flags(YAxisChoice::First, &y_axis_flags)
|
|
||||||
.build(plot_ui, || {
|
|
||||||
PlotLine::new("A line").plot(&vec![2.1, 2.9], &vec![1.1, 1.9]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) {
|
|
||||||
ui.text(im_str!(
|
|
||||||
"This header demos how to use the querying features."
|
|
||||||
));
|
|
||||||
let content_width = ui.window_content_region_width();
|
|
||||||
|
|
||||||
// Create some containers for exfiltrating data from the closure below
|
|
||||||
let mut hover_pos: Option<ImPlotPoint> = None;
|
|
||||||
let mut plot_limits: Option<ImPlotLimits> = None;
|
|
||||||
let mut query_limits: Option<ImPlotLimits> = None;
|
|
||||||
|
|
||||||
// Draw a plot
|
|
||||||
Plot::new("Plot querying")
|
|
||||||
.size(content_width, 300.0)
|
|
||||||
.x_limits(&ImPlotRange { Min: 0.0, Max: 5.0 }, Condition::FirstUseEver)
|
|
||||||
.y_limits(
|
|
||||||
&ImPlotRange { Min: 0.0, Max: 5.0 },
|
|
||||||
YAxisChoice::First,
|
|
||||||
Condition::FirstUseEver,
|
|
||||||
)
|
|
||||||
.with_plot_flags(&(PlotFlags::NONE | PlotFlags::QUERY))
|
|
||||||
.build(plot_ui, || {
|
|
||||||
if is_plot_hovered() {
|
|
||||||
hover_pos = Some(get_plot_mouse_position(None));
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_plot_queried() {
|
|
||||||
query_limits = Some(get_plot_query(None));
|
|
||||||
}
|
|
||||||
plot_limits = Some(get_plot_limits(None));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Print some previously-exfiltrated info. This is because calling
|
|
||||||
// things like is_plot_hovered or get_plot_mouse_position() outside
|
|
||||||
// of an actual Plot is not allowed.
|
|
||||||
if let Some(pos) = hover_pos {
|
|
||||||
ui.text(im_str!("hovered at {}, {}", pos.x, pos.y));
|
|
||||||
}
|
|
||||||
if let Some(limits) = plot_limits {
|
|
||||||
ui.text(im_str!("Plot limits are {:#?}", limits));
|
|
||||||
}
|
|
||||||
if let Some(query) = query_limits {
|
|
||||||
ui.text(im_str!("Query limits are {:#?}", query));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) {
|
|
||||||
ui.text(im_str!(
|
|
||||||
"This header demos how to use the styling features."
|
|
||||||
));
|
|
||||||
let content_width = ui.window_content_region_width();
|
|
||||||
|
|
||||||
// The style stack works the same as for other imgui things - we can push
|
|
||||||
// things to have them apply, then pop again to undo the change. In implot-rs,
|
|
||||||
// pushing returns a value on which we have to call .pop() later. Pushing
|
|
||||||
// variables can be done outside of plot calls as well.
|
|
||||||
let style = push_style_color(&PlotColorElement::PlotBg, 1.0, 1.0, 1.0, 0.2);
|
|
||||||
Plot::new("Style demo plot")
|
|
||||||
.size(content_width, 300.0)
|
|
||||||
.x_limits(&ImPlotRange { Min: 0.0, Max: 6.0 }, Condition::Always)
|
|
||||||
.y_limits(
|
|
||||||
&ImPlotRange {
|
|
||||||
Min: -1.0,
|
|
||||||
Max: 3.0,
|
|
||||||
},
|
|
||||||
YAxisChoice::First,
|
|
||||||
Condition::Always,
|
|
||||||
)
|
|
||||||
.with_plot_flags(&(PlotFlags::NONE))
|
|
||||||
.with_y_axis_flags(YAxisChoice::First, &(AxisFlags::NONE))
|
|
||||||
.build(plot_ui, || {
|
|
||||||
// Markers can be selected as shown here. The markers are internally represented
|
|
||||||
// as an u32, hence this calling style.
|
|
||||||
let markerchoice = push_style_var_i32(&StyleVar::Marker, Marker::Cross as i32);
|
|
||||||
PlotLine::new("Left eye").plot(&vec![2.0, 2.0], &vec![2.0, 1.0]);
|
|
||||||
// Calling pop() on the return value of the push above will undo the marker choice.
|
|
||||||
markerchoice.pop();
|
|
||||||
|
|
||||||
// Line weights can be set the same way, along with some other things - see
|
|
||||||
// the docs of StyleVar for more info.
|
|
||||||
let lineweight = push_style_var_f32(&StyleVar::LineWeight, 5.0);
|
|
||||||
PlotLine::new("Right eye").plot(&vec![4.0, 4.0], &vec![2.0, 1.0]);
|
|
||||||
lineweight.pop();
|
|
||||||
|
|
||||||
let x_values = vec![1.0, 2.0, 4.0, 5.0];
|
|
||||||
let y_values = vec![1.0, 0.0, 0.0, 1.0];
|
|
||||||
PlotLine::new("Mouth").plot(&x_values, &y_values);
|
|
||||||
});
|
|
||||||
|
|
||||||
style.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_colormaps_plot(ui: &Ui, plot_ui: &PlotUi) {
|
|
||||||
ui.text(im_str!("This header demos how to select colormaps."));
|
|
||||||
let content_width = ui.window_content_region_width();
|
|
||||||
|
|
||||||
// Select a colormap from the presets. The presets are listed in the Colormap enum
|
|
||||||
// and usually have something from 9 to 11 colors in them, with the second number
|
|
||||||
// being the option to resample the colormap to a custom number of colors if picked
|
|
||||||
// higher than 1.
|
|
||||||
set_colormap_from_preset(Colormap::Plasma, 1);
|
|
||||||
|
|
||||||
Plot::new("Colormap demo plot")
|
|
||||||
.size(content_width, 300.0)
|
|
||||||
.build(plot_ui, || {
|
|
||||||
(1..10)
|
|
||||||
.map(|x| x as f64 * 0.1)
|
|
||||||
.map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x]))
|
|
||||||
.count();
|
|
||||||
});
|
|
||||||
|
|
||||||
// One can also specify a colormap as a vector of RGBA colors. ImPlot uses ImVec4 for this,
|
|
||||||
// so we follow suit. Make sure to set the last number (w in ImVec4) to 1.0 to see anything -
|
|
||||||
// it's the alpha channel.
|
|
||||||
set_colormap_from_vec(vec![
|
|
||||||
ImVec4 {
|
|
||||||
x: 0.9,
|
|
||||||
y: 0.9,
|
|
||||||
z: 0.0,
|
|
||||||
w: 1.0,
|
|
||||||
},
|
|
||||||
ImVec4 {
|
|
||||||
x: 0.0,
|
|
||||||
y: 0.9,
|
|
||||||
z: 0.9,
|
|
||||||
w: 1.0,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
Plot::new("Colormap demo plot #2")
|
|
||||||
.size(content_width, 300.0)
|
|
||||||
.build(plot_ui, || {
|
|
||||||
(1..10)
|
|
||||||
.map(|x| x as f64 * 0.1)
|
|
||||||
.map(|x| PlotLine::new(&format!("{:3.3}", x)).plot(&vec![0.1, 0.9], &vec![x, x]))
|
|
||||||
.count();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Colormaps are not pushed, they are simply set, because they don't stack or anything.
|
|
||||||
// We can reset to the default by just setting the "Standard" preset.
|
|
||||||
set_colormap_from_preset(Colormap::Standard, 0);
|
|
||||||
}
|
|
Loading…
Reference in a new issue