flow_rs_renderer/
lib.rs

1//! # Flow-RS Renderer
2//!
3//! Rendering abstractions and implementations for Flow-RS.
4//! Supports multiple rendering backends with automatic fallback.
5
6pub mod error;
7pub mod traits;
8
9#[cfg(feature = "canvas2d")]
10pub mod canvas2d;
11
12pub mod performance;
13
14#[cfg(all(test, feature = "canvas2d"))]
15mod canvas2d_tests;
16
17#[cfg(test)]
18pub mod tests;
19
20// TODO: Implement WebGL2 and WebGPU renderers
21// #[cfg(feature = "webgl2")]
22// pub mod webgl2;
23
24// #[cfg(feature = "webgpu")]
25// pub mod webgpu;
26
27// Re-export commonly used types
28pub use error::{RendererError, Result};
29pub use traits::{Renderer, RendererCapabilities, RendererType};
30
31#[cfg(feature = "canvas2d")]
32pub use canvas2d::Canvas2DRenderer;
33
34/// Renderer selection and detection utilities
35pub mod detection {
36    use super::traits::RendererType;
37
38    /// Detect available rendering backends
39    pub fn detect_available_renderers() -> Vec<RendererType> {
40        let mut available = Vec::new();
41
42        #[cfg(feature = "canvas2d")]
43        if is_canvas2d_available() {
44            available.push(RendererType::Canvas2D);
45        }
46
47        #[cfg(feature = "webgl2")]
48        if is_webgl2_available() {
49            available.push(RendererType::WebGL2);
50        }
51
52        #[cfg(feature = "webgpu")]
53        if is_webgpu_available() {
54            available.push(RendererType::WebGPU);
55        }
56
57        available
58    }
59
60    /// Select the best available renderer
61    pub fn select_best_renderer() -> Option<RendererType> {
62        let available = detect_available_renderers();
63
64        // Priority order: WebGPU > WebGL2 > Canvas2D
65        #[cfg(feature = "webgpu")]
66        if available.contains(&RendererType::WebGPU) {
67            return Some(RendererType::WebGPU);
68        }
69
70        #[cfg(feature = "webgl2")]
71        if available.contains(&RendererType::WebGL2) {
72            return Some(RendererType::WebGL2);
73        }
74
75        #[cfg(feature = "canvas2d")]
76        if available.contains(&RendererType::Canvas2D) {
77            return Some(RendererType::Canvas2D);
78        }
79
80        None
81    }
82
83    #[cfg(feature = "canvas2d")]
84    fn is_canvas2d_available() -> bool {
85        // Canvas2D is available in all modern browsers
86        true
87    }
88
89    #[cfg(feature = "webgl2")]
90    fn is_webgl2_available() -> bool {
91        use wasm_bindgen::JsCast;
92        use web_sys::{window, HtmlCanvasElement};
93
94        if let Some(window) = window() {
95            if let Ok(document) = window.document().ok_or("No document") {
96                if let Ok(canvas) = document
97                    .create_element("canvas")
98                    .map_err(|_| "Cannot create canvas")
99                    .and_then(|canvas| {
100                        canvas
101                            .dyn_into::<HtmlCanvasElement>()
102                            .map_err(|_| "Cannot cast to canvas")
103                    })
104                {
105                    return canvas.get_context("webgl2").is_ok();
106                }
107            }
108        }
109        false
110    }
111
112    #[cfg(feature = "webgpu")]
113    fn is_webgpu_available() -> bool {
114        // Check if WebGPU is available
115        #[allow(unused_imports)]
116        use wasm_bindgen::JsCast;
117        use web_sys::window;
118
119        if let Some(window) = window() {
120            if let Ok(navigator) = js_sys::Reflect::get(&window, &"navigator".into()) {
121                return js_sys::Reflect::has(&navigator, &"gpu".into()).unwrap_or(false);
122            }
123        }
124        false
125    }
126}
127
128/// Prelude for convenient imports
129pub mod prelude {
130    pub use super::detection::{detect_available_renderers, select_best_renderer};
131    pub use super::error::{RendererError, Result};
132    pub use super::traits::{Renderer, RendererCapabilities, RendererType};
133
134    #[cfg(feature = "canvas2d")]
135    pub use super::canvas2d::Canvas2DRenderer;
136}