|
| 1 | +mod controls; |
| 2 | +mod scene; |
| 3 | + |
| 4 | +use controls::Controls; |
| 5 | +use scene::Scene; |
| 6 | + |
| 7 | +use iced_wgpu::{ |
| 8 | + wgpu, window::SwapChain, Primitive, Renderer, Settings, Target, |
| 9 | +}; |
| 10 | +use iced_winit::{winit, Cache, Clipboard, MouseCursor, Size, UserInterface}; |
| 11 | + |
| 12 | +use winit::{ |
| 13 | + event::{DeviceEvent, Event, ModifiersState, WindowEvent}, |
| 14 | + event_loop::{ControlFlow, EventLoop}, |
| 15 | +}; |
| 16 | + |
| 17 | +pub fn main() { |
| 18 | + env_logger::init(); |
| 19 | + |
| 20 | + // Initialize winit |
| 21 | + let event_loop = EventLoop::new(); |
| 22 | + let window = winit::window::Window::new(&event_loop).unwrap(); |
| 23 | + let mut logical_size = |
| 24 | + window.inner_size().to_logical(window.scale_factor()); |
| 25 | + let mut modifiers = ModifiersState::default(); |
| 26 | + |
| 27 | + // Initialize WGPU |
| 28 | + let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions { |
| 29 | + power_preference: wgpu::PowerPreference::Default, |
| 30 | + backends: wgpu::BackendBit::PRIMARY, |
| 31 | + }) |
| 32 | + .expect("Request adapter"); |
| 33 | + |
| 34 | + let (mut device, mut queue) = |
| 35 | + adapter.request_device(&wgpu::DeviceDescriptor { |
| 36 | + extensions: wgpu::Extensions { |
| 37 | + anisotropic_filtering: false, |
| 38 | + }, |
| 39 | + limits: wgpu::Limits::default(), |
| 40 | + }); |
| 41 | + |
| 42 | + let surface = wgpu::Surface::create(&window); |
| 43 | + |
| 44 | + let mut swap_chain = { |
| 45 | + let size = window.inner_size(); |
| 46 | + |
| 47 | + SwapChain::new(&device, &surface, size.width, size.height) |
| 48 | + }; |
| 49 | + let mut resized = false; |
| 50 | + |
| 51 | + // Initialize iced |
| 52 | + let mut events = Vec::new(); |
| 53 | + let mut cache = Some(Cache::default()); |
| 54 | + let mut renderer = Renderer::new(&mut device, Settings::default()); |
| 55 | + let mut output = (Primitive::None, MouseCursor::OutOfBounds); |
| 56 | + let clipboard = Clipboard::new(&window); |
| 57 | + |
| 58 | + // Initialize scene and GUI controls |
| 59 | + let mut scene = Scene::new(&device); |
| 60 | + let mut controls = Controls::new(); |
| 61 | + |
| 62 | + // Run event loop |
| 63 | + event_loop.run(move |event, _, control_flow| { |
| 64 | + // You should change this if you want to render continuosly |
| 65 | + *control_flow = ControlFlow::Wait; |
| 66 | + |
| 67 | + match event { |
| 68 | + Event::DeviceEvent { |
| 69 | + event: DeviceEvent::ModifiersChanged(new_modifiers), |
| 70 | + .. |
| 71 | + } => { |
| 72 | + modifiers = new_modifiers; |
| 73 | + } |
| 74 | + Event::WindowEvent { event, .. } => { |
| 75 | + match event { |
| 76 | + WindowEvent::Resized(new_size) => { |
| 77 | + logical_size = |
| 78 | + new_size.to_logical(window.scale_factor()); |
| 79 | + resized = true; |
| 80 | + } |
| 81 | + WindowEvent::CloseRequested => { |
| 82 | + *control_flow = ControlFlow::Exit; |
| 83 | + } |
| 84 | + _ => {} |
| 85 | + } |
| 86 | + |
| 87 | + // Map window event to iced event |
| 88 | + if let Some(event) = iced_winit::conversion::window_event( |
| 89 | + event, |
| 90 | + window.scale_factor(), |
| 91 | + modifiers, |
| 92 | + ) { |
| 93 | + events.push(event); |
| 94 | + } |
| 95 | + } |
| 96 | + Event::MainEventsCleared => { |
| 97 | + // If no relevant events happened, we can simply skip this |
| 98 | + if events.is_empty() { |
| 99 | + return; |
| 100 | + } |
| 101 | + |
| 102 | + // We need to: |
| 103 | + // 1. Process events of our user interface. |
| 104 | + // 2. Update state as a result of any interaction. |
| 105 | + // 3. Generate a new output for our renderer. |
| 106 | + |
| 107 | + // First, we build our user interface. |
| 108 | + let mut user_interface = UserInterface::build( |
| 109 | + controls.view(&scene), |
| 110 | + Size::new(logical_size.width, logical_size.height), |
| 111 | + cache.take().unwrap(), |
| 112 | + &mut renderer, |
| 113 | + ); |
| 114 | + |
| 115 | + // Then, we process the events, obtaining messages in return. |
| 116 | + let messages = user_interface.update( |
| 117 | + events.drain(..), |
| 118 | + clipboard.as_ref().map(|c| c as _), |
| 119 | + &renderer, |
| 120 | + ); |
| 121 | + |
| 122 | + let user_interface = if messages.is_empty() { |
| 123 | + // If there are no messages, no interactions we care about have |
| 124 | + // happened. We can simply leave our user interface as it is. |
| 125 | + user_interface |
| 126 | + } else { |
| 127 | + // If there are messages, we need to update our state |
| 128 | + // accordingly and rebuild our user interface. |
| 129 | + // We can only do this if we drop our user interface first |
| 130 | + // by turning it into its cache. |
| 131 | + cache = Some(user_interface.into_cache()); |
| 132 | + |
| 133 | + // In this example, `Controls` is the only part that cares |
| 134 | + // about messages, so updating our state is pretty |
| 135 | + // straightforward. |
| 136 | + for message in messages { |
| 137 | + controls.update(message, &mut scene); |
| 138 | + } |
| 139 | + |
| 140 | + // Once the state has been changed, we rebuild our updated |
| 141 | + // user interface. |
| 142 | + UserInterface::build( |
| 143 | + controls.view(&scene), |
| 144 | + Size::new(logical_size.width, logical_size.height), |
| 145 | + cache.take().unwrap(), |
| 146 | + &mut renderer, |
| 147 | + ) |
| 148 | + }; |
| 149 | + |
| 150 | + // Finally, we just need to draw a new output for our renderer, |
| 151 | + output = user_interface.draw(&mut renderer); |
| 152 | + |
| 153 | + // update our cache, |
| 154 | + cache = Some(user_interface.into_cache()); |
| 155 | + |
| 156 | + // and request a redraw |
| 157 | + window.request_redraw(); |
| 158 | + } |
| 159 | + Event::RedrawRequested(_) => { |
| 160 | + if resized { |
| 161 | + let size = window.inner_size(); |
| 162 | + |
| 163 | + swap_chain = SwapChain::new( |
| 164 | + &device, |
| 165 | + &surface, |
| 166 | + size.width, |
| 167 | + size.height, |
| 168 | + ); |
| 169 | + } |
| 170 | + |
| 171 | + let (frame, viewport) = swap_chain.next_frame(); |
| 172 | + |
| 173 | + let mut encoder = device.create_command_encoder( |
| 174 | + &wgpu::CommandEncoderDescriptor { todo: 0 }, |
| 175 | + ); |
| 176 | + |
| 177 | + // We draw the scene first |
| 178 | + scene.draw(&mut encoder, &frame.view); |
| 179 | + |
| 180 | + // And then iced on top |
| 181 | + let mouse_cursor = renderer.draw( |
| 182 | + &mut device, |
| 183 | + &mut encoder, |
| 184 | + Target { |
| 185 | + texture: &frame.view, |
| 186 | + viewport, |
| 187 | + }, |
| 188 | + &output, |
| 189 | + window.scale_factor(), |
| 190 | + &["Some debug information!"], |
| 191 | + ); |
| 192 | + |
| 193 | + // Then we submit the work |
| 194 | + queue.submit(&[encoder.finish()]); |
| 195 | + |
| 196 | + // And update the mouse cursor |
| 197 | + window.set_cursor_icon(iced_winit::conversion::mouse_cursor( |
| 198 | + mouse_cursor, |
| 199 | + )); |
| 200 | + } |
| 201 | + _ => {} |
| 202 | + } |
| 203 | + }) |
| 204 | +} |
0 commit comments