autd3_geometry_viewer/
viewer.rs

1/*
2 * File: simulator.rs
3 * Project: src
4 * Created Date: 24/05/2023
5 * Author: Shun Suzuki
6 * -----
7 * Last Modified: 22/09/2023
8 * Modified By: Shun Suzuki (suzuki@hapis.k.u-tokyo.ac.jp)
9 * -----
10 * Copyright (c) 2023 Shun Suzuki. All rights reserved.
11 *
12 */
13
14use crate::{
15    device_viewer::DeviceViewer, imgui_renderer::ImGuiRenderer, model::Model, renderer::Renderer,
16    settings::Settings, Quaternion, Vector3, GL_SCALE,
17};
18
19use autd3_driver::geometry::{Device, Transducer};
20
21use vulkano::{
22    command_buffer::{
23        AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents,
24    },
25    sync::GpuFuture,
26};
27use winit::{
28    event::{Event, WindowEvent},
29    event_loop::{EventLoop, EventLoopBuilder},
30    platform::run_return::EventLoopExtRunReturn,
31};
32
33#[cfg(target_os = "windows")]
34use winit::platform::windows::WindowExtWindows;
35
36/// Viewer for [autd3_core::geometry::Geometry]
37#[derive(Default)]
38pub struct GeometryViewer {
39    window_height: u32,
40    window_width: u32,
41    vsync: bool,
42    settings: Settings,
43}
44
45impl GeometryViewer {
46    pub fn new() -> Self {
47        Self {
48            window_width: 800,
49            window_height: 600,
50            vsync: true,
51            settings: Settings::new(0),
52        }
53    }
54
55    /// Set window size
56    pub fn with_window_size(self, width: u32, height: u32) -> Self {
57        Self {
58            window_width: width,
59            window_height: height,
60            ..self
61        }
62    }
63
64    /// Set vsync
65    pub fn with_vsync(self, vsync: bool) -> Self {
66        Self { vsync, ..self }
67    }
68
69    /// Set settings
70    pub fn with_settings(self, settings: Settings) -> Self {
71        Self { settings, ..self }
72    }
73
74    /// Run viewer
75    ///
76    /// DO NOT call this method multiple times.
77    ///
78    /// # Arguments
79    ///
80    /// * `geometry` - Geometry
81    ///
82    /// # Returns
83    ///
84    /// ## Platform-specific
85    ///
86    /// X11 / Wayland: This function returns 1 upon disconnection from the display server.
87    pub fn run<T: Transducer>(&mut self, devices: &[Device<T>]) -> anyhow::Result<i32> {
88        let mut event_loop = EventLoopBuilder::<()>::with_user_event().build();
89        self.run_with_event_loop(devices, &mut event_loop)
90    }
91
92    /// Create event loop
93    ///
94    /// DO NOT call this method multiple times.
95    pub fn create_event_loop() -> EventLoop<()> {
96        EventLoopBuilder::<()>::with_user_event().build()
97    }
98
99    /// Run viewer with provided event loop
100    ///
101    /// # Arguments
102    ///
103    /// * `geometry` - Geometry
104    /// * `event_loop` - EventLoop
105    ///
106    /// # Returns
107    ///
108    /// ## Platform-specific
109    ///
110    /// X11 / Wayland: This function returns 1 upon disconnection from the display server.
111    #[allow(clippy::let_and_return)]
112    pub fn run_with_event_loop<T: Transducer>(
113        &mut self,
114        devices: &[Device<T>],
115        event_loop: &mut EventLoop<()>,
116    ) -> anyhow::Result<i32> {
117        let mut render = Renderer::new(
118            event_loop,
119            "AUTD GeometryViewer",
120            self.window_width as _,
121            self.window_height as _,
122            self.vsync,
123        );
124        render.window().focus_window();
125
126        let model = Model::new()?;
127        let mut device_viewer = DeviceViewer::new(&render, &model);
128
129        let num_dev = devices.len();
130
131        let geo: Vec<_> = devices
132            .iter()
133            .map(|dev| {
134                let tr = &dev[0];
135                let pos = tr.position();
136                let rot = tr.rotation();
137                (
138                    Vector3::new(pos.x as _, pos.y as _, pos.z as _) * GL_SCALE,
139                    Quaternion::new(rot.w as _, rot.i as _, rot.j as _, rot.k as _),
140                )
141            })
142            .collect();
143
144        let mut settings = self.settings.clone();
145        if settings.shows.len() < num_dev {
146            settings.shows.resize(num_dev, true);
147        }
148
149        render.move_camera(settings.camera_pos(), settings.camera_rot());
150
151        let mut imgui = ImGuiRenderer::new(&render);
152
153        #[cfg(target_os = "windows")]
154        let hwnd = render.window().hwnd();
155
156        let mut is_running = true;
157        let r = event_loop.run_return(move |event, _, control_flow| {
158            match event {
159                Event::WindowEvent {
160                    event: WindowEvent::CloseRequested,
161                    ..
162                } => {
163                    is_running = false;
164                    control_flow.set_exit();
165                }
166                Event::WindowEvent {
167                    event: WindowEvent::Resized(..),
168                    window_id,
169                } if window_id == render.window().id() => {
170                    render.resize();
171                    imgui.resized(render.window(), &event);
172                }
173                Event::WindowEvent {
174                    event:
175                        WindowEvent::ScaleFactorChanged {
176                            scale_factor,
177                            new_inner_size,
178                        },
179                    window_id,
180                } if window_id == render.window().id() => {
181                    *new_inner_size = render
182                        .window()
183                        .inner_size()
184                        .to_logical::<u32>(render.window().scale_factor())
185                        .to_physical(scale_factor);
186                    render.resize();
187                    let event_imgui: Event<'_, ()> = Event::WindowEvent {
188                        window_id,
189                        event: WindowEvent::ScaleFactorChanged {
190                            scale_factor,
191                            new_inner_size,
192                        },
193                    };
194                    imgui.resized(render.window(), &event_imgui);
195                }
196                Event::MainEventsCleared => {
197                    imgui.prepare_frame(render.window());
198                    render.window().request_redraw();
199                }
200                Event::NewEvents(_) => {
201                    imgui.update_delta_time();
202                    render.window().request_redraw();
203                }
204                Event::RedrawRequested(_) => {
205                    let before_pipeline_future = match render.start_frame() {
206                        Err(e) => {
207                            eprintln!("{}", e);
208                            return;
209                        }
210                        Ok(future) => future,
211                    };
212                    let after_future = {
213                        let framebuffer = render.frame_buffer();
214
215                        let mut builder = AutoCommandBufferBuilder::primary(
216                            render.command_buffer_allocator(),
217                            render.queue().queue_family_index(),
218                            CommandBufferUsage::OneTimeSubmit,
219                        )
220                        .unwrap();
221
222                        let clear_values =
223                            vec![Some(settings.background.into()), Some(1f32.into()), None];
224                        builder
225                            .begin_render_pass(
226                                RenderPassBeginInfo {
227                                    clear_values,
228                                    ..RenderPassBeginInfo::framebuffer(framebuffer)
229                                },
230                                SubpassContents::Inline,
231                            )
232                            .unwrap()
233                            .set_viewport(0, [render.viewport()]);
234
235                        render.move_camera(settings.camera_pos(), settings.camera_rot());
236                        let view = render.get_view();
237                        let proj = render.get_projection(
238                            settings.camera_fov,
239                            settings.camera_near_clip,
240                            settings.camera_far_clip,
241                        );
242
243                        device_viewer.render(&model, &geo, (view, proj), &settings, &mut builder);
244
245                        builder.end_render_pass().unwrap();
246
247                        imgui.render(&render, &geo, &mut settings, &mut builder);
248
249                        let command_buffer = builder.build().unwrap();
250
251                        let future = before_pipeline_future
252                            .then_execute(render.queue(), command_buffer)
253                            .unwrap();
254
255                        future.boxed()
256                    };
257
258                    render.finish_frame(after_future);
259                }
260                event => {
261                    imgui.handle_event(render.window(), &event);
262                }
263            }
264            if !is_running {
265                control_flow.set_exit();
266            }
267        });
268
269        #[cfg(target_os = "windows")]
270        unsafe {
271            let _ = windows::Win32::UI::WindowsAndMessaging::DestroyWindow(
272                windows::Win32::Foundation::HWND(hwnd),
273            );
274        }
275
276        Ok(r)
277    }
278}