use std::sync::Arc;
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop as WinitEventLoop};
use winit::window::{Window, WindowId as WinitWindowId};
use vello::util::{RenderContext, RenderSurface};
use vello::wgpu::PresentMode;
use vello::Scene;
#[derive(Debug, Clone)]
pub struct AppConfig {
pub title: String,
pub width: u32,
pub height: u32,
}
impl Default for AppConfig {
fn default() -> Self {
Self {
title: "UZOR Application".to_string(),
width: 1280,
height: 720,
}
}
}
impl AppConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = title.into();
self
}
pub fn with_size(mut self, width: u32, height: u32) -> Self {
self.width = width;
self.height = height;
self
}
}
pub struct RenderSurfaceProvider {
pub window: Arc<Window>,
pub render_context: RenderContext,
pub surface: RenderSurface<'static>,
pub scene: Scene,
}
impl RenderSurfaceProvider {
pub fn new(window: Arc<Window>) -> Self {
let mut render_context = RenderContext::new();
let size = window.inner_size();
let surface = pollster::block_on(render_context.create_surface(
window.clone(),
size.width,
size.height,
PresentMode::AutoVsync,
))
.expect("Failed to create surface");
Self {
window,
render_context,
surface,
scene: Scene::new(),
}
}
pub fn scale_factor(&self) -> f64 {
self.window.scale_factor()
}
pub fn size(&self) -> (u32, u32) {
let size = self.window.inner_size();
(size.width, size.height)
}
pub fn resize(&mut self, width: u32, height: u32) {
self.render_context.resize_surface(&mut self.surface, width, height);
}
pub fn request_redraw(&self) {
self.window.request_redraw();
}
}
pub type EventCallback = dyn FnMut(&mut RenderSurfaceProvider, WindowEvent) -> bool;
pub struct Application {
config: AppConfig,
event_callback: Box<EventCallback>,
}
impl Application {
pub fn new(config: AppConfig, event_callback: Box<EventCallback>) -> Self {
Self {
config,
event_callback,
}
}
pub fn with_default_config(event_callback: Box<EventCallback>) -> Self {
Self::new(AppConfig::default(), event_callback)
}
pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
let event_loop = WinitEventLoop::new()?;
event_loop.set_control_flow(ControlFlow::Poll);
let mut app_handler = AppHandler::new(self.config, self.event_callback);
event_loop.run_app(&mut app_handler)?;
Ok(())
}
}
struct AppHandler {
config: AppConfig,
event_callback: Box<EventCallback>,
surface_provider: Option<RenderSurfaceProvider>,
}
impl AppHandler {
fn new(config: AppConfig, event_callback: Box<EventCallback>) -> Self {
Self {
config,
event_callback,
surface_provider: None,
}
}
fn create_window(&mut self, event_loop: &ActiveEventLoop) {
let window_attrs = Window::default_attributes()
.with_title(self.config.title.clone())
.with_inner_size(winit::dpi::LogicalSize::new(
self.config.width,
self.config.height,
));
let window = match event_loop.create_window(window_attrs) {
Ok(w) => Arc::new(w),
Err(e) => {
eprintln!("Failed to create window: {}", e);
return;
}
};
self.surface_provider = Some(RenderSurfaceProvider::new(window));
}
}
impl ApplicationHandler for AppHandler {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if self.surface_provider.is_none() {
self.create_window(event_loop);
}
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
_window_id: WinitWindowId,
event: WindowEvent,
) {
if let WindowEvent::CloseRequested = event {
event_loop.exit();
return;
}
if let WindowEvent::Resized(size) = event {
if let Some(provider) = self.surface_provider.as_mut() {
provider.resize(size.width, size.height);
}
}
if let Some(provider) = self.surface_provider.as_mut() {
let should_continue = (self.event_callback)(provider, event);
if !should_continue {
event_loop.exit();
}
}
}
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
}
}