cotis-wgpu 0.1.0-alpha

Desktop wgpu renderer backend for Cotis
Documentation
//! Cotis context and interactivity trait implementations for [`crate::renderer::CotisWgpuRenderer`].
//!
//! These impls connect the renderer to the Cotis application framework. They are defined here
//! rather than in [`crate::renderer`] to keep the renderer module focused on GPU/window logic.
//!
//! | Trait | Behavior |
//! |-------|----------|
//! | [`cotis_utils::traits::CotisWindowContext`] | Returns physical window dimensions in pixels from winit `inner_size`. |
//! | [`cotis_utils::traits::CotisFrameContext`] | Returns elapsed time since the previous frame. |
//! | [`cotis_utils::traits::CotisRenderContext`] | Provided automatically via blanket impl when window and frame contexts are implemented. |
//! | [`cotis_utils::text::RendererTextMeasuringProvider`] | Glyphon measurement with DPI-scaled font metrics. **`font_id` is ignored**; always uses `Family::SansSerif`. |
//! | [`cotis_utils::interactivity::mouse::MouseProvider`] | Reads cursor position, button state, and scroll delta from [`crate::input::InputSnapshot`]. |
//! | [`cotis_utils::interactivity::keyboard::SimpleKeyboardProvider`] | Reads pressed keys from [`crate::input::InputSnapshot`]. |
//! | [`cotis_utils::interactivity::keyboard::SimpleTextProvider`] | Reads IME/preedit characters from [`crate::input::InputSnapshot`]. |

use indexmap::IndexSet;

use cotis_defaults::element_configs::text_config::TextConfig;
use cotis_utils::interactivity::keyboard::{
    KeyboardKey, SimpleKeyboardProvider, SimpleTextProvider,
};
use cotis_utils::interactivity::mouse::{MouseButton, MouseProvider};
use cotis_utils::math::{Dimensions, Vector2};
use cotis_utils::text::RendererTextMeasuringProvider;
use cotis_utils::traits::{CotisFrameContext, CotisWindowContext};

use crate::renderer::CotisWgpuRenderer;

impl CotisWindowContext for CotisWgpuRenderer {
    fn window_dimensions(&self) -> Dimensions {
        self.window_dimensions()
    }
}

impl CotisFrameContext for CotisWgpuRenderer {
    fn get_delta_time(&self) -> f32 {
        self.delta_time()
    }
}

impl RendererTextMeasuringProvider<TextConfig> for CotisWgpuRenderer {
    fn provide_measurer(&mut self) -> Box<dyn Fn(&str, &TextConfig) -> Dimensions> {
        let font_system = self.text().font_system();
        let dpi_scale = self.dpi_scale();
        Box::new(move |text: &str, config: &TextConfig| {
            let mut font_system = match font_system.lock() {
                Ok(guard) => guard,
                Err(error) => {
                    log::error!("font system mutex poisoned: {error}");
                    error.into_inner()
                }
            };
            let font_size = config.font_size * dpi_scale;
            let line_height = if config.line_height > 0.0 {
                config.line_height * dpi_scale
            } else {
                font_size * 1.5
            };

            use glyphon::{Attrs, Buffer, Family, Metrics, Shaping};
            let mut buffer = Buffer::new(&mut font_system, Metrics::new(font_size, line_height));
            buffer.set_text(
                &mut font_system,
                text,
                Attrs::new().family(Family::SansSerif),
                Shaping::Advanced,
            );
            buffer.shape_until_scroll(&mut font_system, false);
            let line_width = buffer
                .layout_runs()
                .next()
                .map(|run| run.line_w)
                .unwrap_or(0.0);
            Dimensions::new(line_width, buffer.metrics().line_height)
        })
    }
}

impl MouseProvider for CotisWgpuRenderer {
    fn get_mouse_position(&self) -> Vector2 {
        self.input().mouse_position
    }

    fn mouse_button_down(&self, button: MouseButton) -> bool {
        self.input().mouse_buttons.contains(&button)
    }

    fn get_mouse_wheel_move_v(&self) -> Vector2 {
        self.input().scroll_delta
    }
}

impl SimpleKeyboardProvider for CotisWgpuRenderer {
    fn get_pressed_keys(&self) -> IndexSet<KeyboardKey> {
        self.input().pressed_keys.clone()
    }
}

impl SimpleTextProvider for CotisWgpuRenderer {
    fn get_pressed_chars(&self) -> Vec<char> {
        self.input().pressed_chars.clone()
    }
}