extern crate alloc; use crate::abi::datastructures::{Color, RenderingPrimitive}; use cgmath::Matrix4; use std::cell::RefCell; use std::rc::Rc; pub enum FillStyle { SolidColor(Color), } pub trait HasRenderingPrimitive { fn primitive(&self) -> &RenderingPrimitive; } pub trait Frame { type LowLevelRenderingPrimitive: HasRenderingPrimitive; fn render_primitive( &mut self, primitive: &Self::LowLevelRenderingPrimitive, transform: &Matrix4, ); } pub trait RenderingPrimitivesBuilder { type LowLevelRenderingPrimitive: HasRenderingPrimitive; fn create(&mut self, primitive: RenderingPrimitive) -> Self::LowLevelRenderingPrimitive; } pub trait GraphicsBackend: Sized { type LowLevelRenderingPrimitive: HasRenderingPrimitive; type Frame: Frame; type RenderingPrimitivesBuilder: RenderingPrimitivesBuilder< LowLevelRenderingPrimitive = Self::LowLevelRenderingPrimitive, >; fn new_rendering_primitives_builder(&mut self) -> Self::RenderingPrimitivesBuilder; fn finish_primitives(&mut self, builder: Self::RenderingPrimitivesBuilder); fn new_frame(&mut self, width: u32, height: u32, clear_color: &Color) -> Self::Frame; fn present_frame(&mut self, frame: Self::Frame); fn window(&self) -> &winit::window::Window; } enum RenderingCacheEntry { AllocateEntry(RenderingPrimitive), FreeEntry(Option), // contains next free index if exists } pub struct RenderingCache { nodes: Vec>, next_free: Option, len: usize, } impl Default for RenderingCache { fn default() -> Self { Self { nodes: vec![], next_free: None, len: 0 } } } impl RenderingCache { pub fn allocate_entry(&mut self, content: Backend::LowLevelRenderingPrimitive) -> usize { let idx = { if let Some(free_idx) = self.next_free { let node = &mut self.nodes[free_idx]; if let RenderingCacheEntry::FreeEntry(next_free) = node { self.next_free = *next_free; } else { unreachable!(); } *node = RenderingCacheEntry::AllocateEntry(content); free_idx } else { self.nodes.push(RenderingCacheEntry::AllocateEntry(content)); self.nodes.len() - 1 } }; self.len = self.len + 1; idx } pub fn entry_at(&self, idx: usize) -> &Backend::LowLevelRenderingPrimitive { match self.nodes[idx] { RenderingCacheEntry::AllocateEntry(ref data) => return data, _ => unreachable!(), } } pub fn set_entry_at(&mut self, idx: usize, primitive: Backend::LowLevelRenderingPrimitive) { match self.nodes[idx] { RenderingCacheEntry::AllocateEntry(ref mut data) => *data = primitive, _ => unreachable!(), } } pub fn free_entry(&mut self, idx: usize) { self.len = self.len - 1; self.nodes[idx] = RenderingCacheEntry::FreeEntry(self.next_free); self.next_free = Some(idx); } pub fn len(&self) -> usize { self.len } } pub struct GraphicsWindow { graphics_backend_factory: Box Backend>, graphics_backend: Option, rendering_cache: RenderingCache, } impl GraphicsWindow { pub fn new( graphics_backend_factory: impl Fn(&crate::eventloop::EventLoop, winit::window::WindowBuilder) -> Backend + 'static, ) -> Rc> { let this = Rc::new(RefCell::new(Self { graphics_backend_factory: Box::new(graphics_backend_factory), graphics_backend: None, rendering_cache: RenderingCache::default(), })); this } pub fn id(&self) -> Option { self.graphics_backend.as_ref().map(|backend| backend.window().id()) } } impl Drop for GraphicsWindow { fn drop(&mut self) { if let Some(backend) = self.graphics_backend.as_ref() { crate::eventloop::unregister_window(backend.window().id()); } } } impl crate::eventloop::GenericWindow for RefCell> { fn draw(&self, component: crate::ComponentRefPin) { let mut this = self.borrow_mut(); { let mut rendering_primitives_builder = this.graphics_backend.as_mut().unwrap().new_rendering_primitives_builder(); // Generate cached rendering data once crate::item_tree::visit_items( component, |_, item, _| { crate::item_rendering::update_item_rendering_data( item, &mut this.rendering_cache, &mut rendering_primitives_builder, ); }, (), ); this.graphics_backend.as_mut().unwrap().finish_primitives(rendering_primitives_builder); } let window = this.graphics_backend.as_ref().unwrap().window(); let size = window.inner_size(); let mut frame = this.graphics_backend.as_mut().unwrap().new_frame( size.width, size.height, &Color::WHITE, ); crate::item_rendering::render_component_items( component, &mut frame, &mut this.rendering_cache, ); this.graphics_backend.as_mut().unwrap().present_frame(frame); } fn process_mouse_input( &self, pos: winit::dpi::PhysicalPosition, state: winit::event::ElementState, component: crate::ComponentRefPin, ) { crate::input::process_mouse_event( component, crate::abi::datastructures::MouseEvent { pos: euclid::point2(pos.x as _, pos.y as _), what: match state { winit::event::ElementState::Pressed => { crate::abi::datastructures::MouseEventType::MousePressed } winit::event::ElementState::Released => { crate::abi::datastructures::MouseEventType::MouseReleased } }, }, ); } fn window_handle(&self) -> std::cell::Ref { std::cell::Ref::map(self.borrow(), |mw| mw.graphics_backend.as_ref().unwrap().window()) } fn map_window(self: Rc, event_loop: &crate::eventloop::EventLoop) { if self.borrow().graphics_backend.is_some() { return; } let id = { let window_builder = winit::window::WindowBuilder::new(); let mut this = self.borrow_mut(); let factory = this.graphics_backend_factory.as_mut(); let backend = factory(&event_loop, window_builder); let window_id = backend.window().id(); this.graphics_backend = Some(backend); window_id }; crate::eventloop::register_window( id, self.clone() as Rc, ); } fn request_redraw(&self) { if let Some(backend) = self.borrow().graphics_backend.as_ref() { backend.window().request_redraw(); } } }