use ferroui_base::platform::surfaces::IPlatformRenderSurface;
use ferroui_base::rendering::composition::{CompositingRenderer, CompositionTransparencyLevel, Compositor};
use ferroui_base::rendering::{IHitTester, IPresentationSource, IRenderer};
use ferroui_base::{FerroLocator, LocatorExtensions, Ref, Visual};
use std::any::Any;
use std::rc::Rc;
pub type RenderSurfaces = std::sync::Arc<dyn Fn() -> Vec<std::sync::Arc<dyn IPlatformRenderSurface>> + Send + Sync>;
pub trait ITopLevelRenderer: IRenderer {
fn set_root(&self, _root: Option<Ref<Visual>>) {}
fn set_transparency_level(&self, _level: CompositionTransparencyLevel) {}
fn set_platform_specific_scene_info(&self, _info: Option<std::sync::Arc<dyn Any + Send + Sync>>) {}
fn hit_tester(&self) -> Option<Rc<dyn IHitTester>> {
None
}
fn as_any(&self) -> &dyn Any;
}
impl ITopLevelRenderer for CompositingRenderer {
fn set_root(&self, root: Option<Ref<Visual>>) {
CompositingRenderer::set_root(self, root)
}
fn set_transparency_level(&self, level: CompositionTransparencyLevel) {
CompositingRenderer::set_transparency_level(self, level)
}
fn set_platform_specific_scene_info(&self, info: Option<std::sync::Arc<dyn Any + Send + Sync>>) {
CompositingRenderer::set_platform_specific_scene_info(self, info)
}
fn hit_tester(&self) -> Option<Rc<dyn IHitTester>> {
CompositingRenderer::hit_tester(self)
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub trait IRendererFactory {
fn create_renderer(
&self,
root: Rc<dyn IPresentationSource>,
compositor: Option<Rc<Compositor>>,
surfaces: RenderSurfaces,
) -> Rc<dyn ITopLevelRenderer>;
}
impl<F> IRendererFactory for F
where
F: Fn(Rc<dyn IPresentationSource>, Option<Rc<Compositor>>, RenderSurfaces) -> Rc<dyn ITopLevelRenderer>,
{
fn create_renderer(
&self,
root: Rc<dyn IPresentationSource>,
compositor: Option<Rc<Compositor>>,
surfaces: RenderSurfaces,
) -> Rc<dyn ITopLevelRenderer> {
self(root, compositor, surfaces)
}
}
pub fn create_renderer(
root: Rc<dyn IPresentationSource>,
compositor: Option<Rc<Compositor>>,
surfaces: RenderSurfaces,
) -> Rc<dyn ITopLevelRenderer> {
if let Some(factory) = FerroLocator::current().get_service::<dyn IRendererFactory>() {
return factory.create_renderer(root, compositor, surfaces);
}
let Some(compositor) = compositor else {
panic!("Could not create a renderer: the platform has no compositor and no renderer factory is registered. Was a rendering subsystem initialized?")
};
CompositingRenderer::new(&root, &compositor, surfaces)
}