iced-yoda/examples/integration/src/main.rs

400 lines
14 KiB
Rust
Raw Normal View History

mod controls;
mod scene;
use controls::Controls;
use scene::Scene;
use iced_wgpu::graphics::{Shell, Viewport};
2025-02-21 01:28:47 +01:00
use iced_wgpu::{Engine, Renderer, wgpu};
use iced_winit::Clipboard;
use iced_winit::conversion;
use iced_winit::core::mouse;
use iced_winit::core::renderer;
2025-03-04 19:11:37 +01:00
use iced_winit::core::time::Instant;
use iced_winit::core::window;
2025-03-04 19:11:37 +01:00
use iced_winit::core::{Event, Font, Pixels, Size, Theme};
use iced_winit::futures;
2025-03-04 19:11:37 +01:00
use iced_winit::runtime::user_interface::{self, UserInterface};
use iced_winit::winit;
use winit::{
2024-05-07 15:50:18 +02:00
event::WindowEvent,
event_loop::{ControlFlow, EventLoop},
2023-12-15 13:15:44 +01:00
keyboard::ModifiersState,
};
use std::sync::Arc;
2024-05-07 15:50:18 +02:00
pub fn main() -> Result<(), winit::error::EventLoopError> {
tracing_subscriber::fmt::init();
// Initialize winit
2023-12-15 13:15:44 +01:00
let event_loop = EventLoop::new()?;
2024-05-07 15:50:18 +02:00
#[allow(clippy::large_enum_variant)]
enum Runner {
Loading,
Ready {
window: Arc<winit::window::Window>,
queue: wgpu::Queue,
device: wgpu::Device,
2024-05-07 15:50:18 +02:00
surface: wgpu::Surface<'static>,
format: wgpu::TextureFormat,
renderer: Renderer,
scene: Scene,
2025-03-04 19:11:37 +01:00
controls: Controls,
events: Vec<Event>,
cursor: mouse::Cursor,
cache: user_interface::Cache,
2024-05-07 15:50:18 +02:00
clipboard: Clipboard,
viewport: Viewport,
modifiers: ModifiersState,
resized: bool,
},
2024-05-07 15:50:18 +02:00
}
impl winit::application::ApplicationHandler for Runner {
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
if let Self::Loading = self {
let window = Arc::new(
event_loop
.create_window(
winit::window::WindowAttributes::default(),
)
.expect("Create window"),
);
let physical_size = window.inner_size();
let viewport = Viewport::with_physical_size(
Size::new(physical_size.width, physical_size.height),
2025-09-02 23:29:22 +02:00
window.scale_factor() as f32,
2024-05-07 15:50:18 +02:00
);
2024-08-12 03:10:46 +02:00
let clipboard = Clipboard::connect(window.clone());
2024-05-07 15:50:18 +02:00
let backend = wgpu::Backends::from_env().unwrap_or_default();
2024-05-07 15:50:18 +02:00
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
2024-05-07 15:50:18 +02:00
backends: backend,
..Default::default()
});
let surface = instance
.create_surface(window.clone())
.expect("Create window surface");
let (format, adapter, device, queue) =
futures::futures::executor::block_on(async {
let adapter =
wgpu::util::initialize_adapter_from_env_or_default(
&instance,
Some(&surface),
)
.await
.expect("Create adapter");
2020-06-02 16:48:55 -04:00
2024-05-07 15:50:18 +02:00
let adapter_features = adapter.features();
2024-05-07 15:50:18 +02:00
let capabilities = surface.get_capabilities(&adapter);
2024-05-07 15:50:18 +02:00
let (device, queue) = adapter
2025-07-22 02:50:42 +02:00
.request_device(&wgpu::DeviceDescriptor {
label: None,
required_features: adapter_features
& wgpu::Features::default(),
required_limits: wgpu::Limits::default(),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::Off,
2025-10-31 14:11:20 +01:00
experimental_features:
wgpu::ExperimentalFeatures::disabled(),
2025-07-22 02:50:42 +02:00
})
2024-05-07 15:50:18 +02:00
.await
.expect("Request device");
(
capabilities
.formats
.iter()
.copied()
.find(wgpu::TextureFormat::is_srgb)
.or_else(|| {
capabilities.formats.first().copied()
})
.expect("Get preferred format"),
adapter,
device,
queue,
)
});
surface.configure(
&device,
&wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format,
width: physical_size.width,
height: physical_size.height,
present_mode: wgpu::PresentMode::AutoVsync,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
view_formats: vec![],
desired_maximum_frame_latency: 2,
},
2024-05-07 15:50:18 +02:00
);
// Initialize scene and GUI controls
let scene = Scene::new(&device, format);
let controls = Controls::new();
// Initialize iced
2025-04-01 02:18:20 +02:00
let renderer = {
let engine = Engine::new(
&adapter,
device.clone(),
queue.clone(),
2025-04-01 02:18:20 +02:00
format,
None,
Shell::headless(),
2025-04-01 02:18:20 +02:00
);
2024-05-07 15:50:18 +02:00
2025-04-01 02:18:20 +02:00
Renderer::new(engine, Font::default(), Pixels::from(16))
};
2024-05-07 15:50:18 +02:00
// You should change this if you want to render continuously
event_loop.set_control_flow(ControlFlow::Wait);
*self = Self::Ready {
window,
device,
queue,
2024-05-07 15:50:18 +02:00
renderer,
surface,
format,
2024-05-07 15:50:18 +02:00
scene,
2025-03-04 19:11:37 +01:00
controls,
events: Vec::new(),
cursor: mouse::Cursor::Unavailable,
2024-05-07 15:50:18 +02:00
modifiers: ModifiersState::default(),
2025-03-04 19:11:37 +01:00
cache: user_interface::Cache::new(),
2024-05-07 15:50:18 +02:00
clipboard,
viewport,
resized: false,
};
}
}
2024-05-07 15:50:18 +02:00
fn window_event(
&mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
_window_id: winit::window::WindowId,
event: WindowEvent,
) {
let Self::Ready {
window,
device,
queue,
2024-05-07 15:50:18 +02:00
surface,
format,
renderer,
scene,
2025-03-04 19:11:37 +01:00
controls,
events,
2024-05-07 15:50:18 +02:00
viewport,
2025-03-04 19:11:37 +01:00
cursor,
2024-05-07 15:50:18 +02:00
modifiers,
clipboard,
2025-03-04 19:11:37 +01:00
cache,
2024-05-07 15:50:18 +02:00
resized,
} = self
else {
return;
};
match event {
WindowEvent::RedrawRequested => {
if *resized {
let size = window.inner_size();
*viewport = Viewport::with_physical_size(
Size::new(size.width, size.height),
2025-09-02 23:29:22 +02:00
window.scale_factor() as f32,
);
2021-08-19 03:06:35 +02:00
2024-05-07 15:50:18 +02:00
surface.configure(
device,
&wgpu::SurfaceConfiguration {
format: *format,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::AutoVsync,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
view_formats: vec![],
desired_maximum_frame_latency: 2,
},
);
2021-08-19 03:06:35 +02:00
2024-05-07 15:50:18 +02:00
*resized = false;
}
match surface.get_current_texture() {
Ok(frame) => {
let view = frame.texture.create_view(
&wgpu::TextureViewDescriptor::default(),
);
let mut encoder = device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { label: None },
);
2024-05-07 15:50:18 +02:00
{
// Clear the frame
2024-05-07 15:50:18 +02:00
let mut render_pass = Scene::clear(
&view,
&mut encoder,
2025-03-04 19:11:37 +01:00
controls.background_color(),
2024-05-07 15:50:18 +02:00
);
// Draw the scene
scene.draw(&mut render_pass);
}
// Submit the scene
queue.submit([encoder.finish()]);
// Draw iced on top
2025-03-04 19:11:37 +01:00
let mut interface = UserInterface::build(
controls.view(),
viewport.logical_size(),
std::mem::take(cache),
renderer,
);
let (state, _) = interface.update(
2025-03-04 19:11:37 +01:00
&[Event::Window(
window::Event::RedrawRequested(
Instant::now(),
),
)],
*cursor,
renderer,
clipboard,
&mut Vec::new(),
);
// Update the mouse cursor
if let user_interface::State::Updated {
mouse_interaction,
..
} = state
{
2024-12-04 18:40:42 -07:00
// Update the mouse cursor
if let Some(icon) =
iced_winit::conversion::mouse_interaction(
mouse_interaction,
2024-12-04 18:40:42 -07:00
)
{
window.set_cursor(icon);
window.set_cursor_visible(true);
} else {
window.set_cursor_visible(false);
}
}
// Draw the interface
interface.draw(
2025-03-04 19:11:37 +01:00
renderer,
&Theme::Dark,
&renderer::Style::default(),
*cursor,
);
*cache = interface.into_cache();
2024-05-07 15:50:18 +02:00
renderer.present(
None,
frame.texture.format(),
&view,
2024-05-07 15:50:18 +02:00
viewport,
);
// Present the frame
2024-05-07 15:50:18 +02:00
frame.present();
}
2024-05-07 15:50:18 +02:00
Err(error) => match error {
wgpu::SurfaceError::OutOfMemory => {
panic!(
"Swapchain error: {error}. \
2025-03-04 19:11:37 +01:00
Rendering cannot continue."
2024-05-07 15:50:18 +02:00
)
}
_ => {
// Try rendering again next frame.
window.request_redraw();
}
},
2023-12-15 13:15:44 +01:00
}
}
2024-05-07 15:50:18 +02:00
WindowEvent::CursorMoved { position, .. } => {
2025-03-04 19:11:37 +01:00
*cursor =
mouse::Cursor::Available(conversion::cursor_position(
position,
viewport.scale_factor(),
));
2024-05-07 15:50:18 +02:00
}
WindowEvent::ModifiersChanged(new_modifiers) => {
*modifiers = new_modifiers.state();
2023-12-15 13:15:44 +01:00
}
2024-05-07 15:50:18 +02:00
WindowEvent::Resized(_) => {
*resized = true;
}
WindowEvent::CloseRequested => {
event_loop.exit();
}
_ => {}
2023-12-15 13:15:44 +01:00
}
2024-05-07 15:50:18 +02:00
// Map window event to iced event
2025-03-04 19:11:37 +01:00
if let Some(event) = conversion::window_event(
2024-05-07 15:50:18 +02:00
event,
2025-09-02 23:29:22 +02:00
window.scale_factor() as f32,
2024-05-07 15:50:18 +02:00
*modifiers,
) {
2025-03-04 19:11:37 +01:00
events.push(event);
2024-05-07 15:50:18 +02:00
}
// If there are events pending
2025-03-04 19:11:37 +01:00
if !events.is_empty() {
// We process them
let mut interface = UserInterface::build(
controls.view(),
2024-05-07 15:50:18 +02:00
viewport.logical_size(),
2025-03-04 19:11:37 +01:00
std::mem::take(cache),
renderer,
);
let mut messages = Vec::new();
let _ = interface.update(
events,
*cursor,
2024-05-07 15:50:18 +02:00
renderer,
clipboard,
2025-03-04 19:11:37 +01:00
&mut messages,
2024-05-07 15:50:18 +02:00
);
2025-03-04 19:11:37 +01:00
events.clear();
*cache = interface.into_cache();
// update our UI with any messages
for message in messages {
controls.update(message);
}
2024-05-07 15:50:18 +02:00
// and request a redraw
window.request_redraw();
}
2023-12-15 13:15:44 +01:00
}
2024-05-07 15:50:18 +02:00
}
2023-12-15 13:15:44 +01:00
2024-05-07 15:50:18 +02:00
let mut runner = Runner::Loading;
event_loop.run_app(&mut runner)
}