pierro 0.1.0

An immediate mode UI library for Rust
Documentation

use std::sync::Arc;

use winit::{
    dpi::{LogicalSize, PhysicalSize, Size}, event_loop::ActiveEventLoop, window::{Icon, Window, WindowAttributes}
};

use crate::{text::TextResources, PainterResources, WindowConfig};

use super::{TextRenderCache, Vec2};

pub(crate) struct RenderResources<'a> {
    pub(crate) window: Arc<Window>,

    pub(crate) surface: wgpu::Surface<'a>,
    pub(crate) device: wgpu::Device,
    pub(crate) queue: wgpu::Queue,
    pub(crate) config: wgpu::SurfaceConfiguration,
    pub(crate) physical_size: PhysicalSize<u32>,

    pub(crate) text_resources: TextResources,
    pub(crate) paint_resources: PainterResources,

    pub(crate) text_render_cache: TextRenderCache
}

impl RenderResources<'_> {

    pub(crate) async fn new(event_loop: &ActiveEventLoop, config: WindowConfig) -> Option<Self> {

        let icon = Icon::from_rgba(config.icon.rgba, config.icon.width, config.icon.height).ok();

        let window_attributes = WindowAttributes::default()
            .with_min_inner_size(Size::Logical(LogicalSize::new(config.min_size.x as f64, config.min_size.y as f64)))
            .with_window_icon(icon)
            .with_title(config.title);
        let window = Arc::new(event_loop.create_window(window_attributes).ok()?);
        let size = window.inner_size();

        let instance = wgpu::Instance::default();
        let surface = instance.create_surface(window.clone()).ok()?;
        let adapter = instance.request_adapter(&wgpu::RequestAdapterOptionsBase {
            power_preference: wgpu::PowerPreference::LowPower,
            force_fallback_adapter: false,
            compatible_surface: Some(&surface) 
        }).await?;
        let (device, queue) = adapter.request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                required_features: wgpu::Features::default(),
                required_limits: wgpu::Limits::default(),
                memory_hints: Default::default(),
            },
            None
        ).await.ok()?;
        let surface_caps = surface.get_capabilities(&adapter);
        let surface_format = surface_caps.formats.iter()
            .find(|format| !format.is_srgb())
            .copied()
            .unwrap_or(surface_caps.formats[0]);
        let config = wgpu::SurfaceConfiguration {
            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
            format: surface_format,
            width: size.width,
            height: size.height,
            present_mode: if surface_caps.present_modes.contains(&wgpu::PresentMode::Fifo) {
                wgpu::PresentMode::Fifo
            } else {
                surface_caps.present_modes[0] 
            },
            alpha_mode: surface_caps.alpha_modes[0],
            view_formats: vec![],
            desired_maximum_frame_latency: 2,
        };

        let paint_resources = PainterResources::new(&device, config.format);

        let text_resources = TextResources::new(&device);
        let text_render_cache = TextRenderCache::new();

        Some(Self {
            window,
            surface,
            device,
            queue,
            config,
            physical_size: size,
            paint_resources,
            text_resources,
            text_render_cache
        })
    }

    pub(crate) fn begin_frame(&mut self, screen_size: Vec2) {
        self.paint_resources.begin_frame(&self.queue, screen_size);
    }

    pub(crate) fn resize(&mut self, new_size: PhysicalSize<u32>) {
        if new_size.width > 0 && new_size.height > 0 {
            self.physical_size = new_size;
            self.config.width = new_size.width;
            self.config.height = new_size.height;
            self.surface.configure(&self.device, &self.config);
        }
    }

    pub(crate) fn request_redraw(&self) {
        self.window.request_redraw();
    }

}