Skip to main content

oxframe_render/
lib.rs

1//! Renderers turn a [`SceneGraph`] into an RGBA image.
2//!
3//! [`CpuRenderer`] (tiny-skia) is the reference backend and the `--cpu`
4//! mode for machines without a GPU; `GpuRenderer` (vello, feature `gpu`) is
5//! the fast path. Both consume the same [`oxframe_2d::DrawItem`] list and pass
6//! the same golden tests within a ΔE tolerance.
7
8#![warn(missing_docs)]
9
10use kurbo::Affine;
11use oxframe_2d::SceneGraph;
12use oxframe_core::Color;
13
14#[cfg(feature = "cpu")]
15mod blur;
16#[cfg(feature = "cpu")]
17mod cpu;
18#[cfg(feature = "cpu")]
19pub use cpu::CpuRenderer;
20
21#[cfg(feature = "gpu")]
22mod gpu;
23#[cfg(feature = "gpu")]
24pub use gpu::{GpuError, GpuRenderer};
25
26/// 8-bit sRGB RGBA, straight alpha, row-major, no padding.
27#[derive(Clone, PartialEq, Eq)]
28pub struct Image {
29    /// Width in pixels.
30    pub width: u32,
31    /// Height in pixels.
32    pub height: u32,
33    /// `width * height * 4` bytes.
34    pub data: Vec<u8>,
35}
36
37impl std::fmt::Debug for Image {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        write!(f, "Image({}x{})", self.width, self.height)
40    }
41}
42
43/// Size and background of one render call.
44#[derive(Debug, Clone, Copy)]
45pub struct RenderOptions {
46    /// Output size; the scene is scaled uniformly to fit and centered.
47    pub width: u32,
48    /// Output height in pixels.
49    pub height: u32,
50    /// Color drawn under the scene.
51    pub background: Color,
52}
53
54/// Draws a scene graph into an image.
55pub trait Renderer {
56    /// Draws the current state of `graph`.
57    fn render(&mut self, graph: &SceneGraph, options: &RenderOptions) -> Image;
58}
59
60/// Maps scene coordinates (origin at the center, y down) to output pixels.
61pub fn scene_to_pixels(scene: (u32, u32), out: (u32, u32)) -> Affine {
62    let (sw, sh) = (f64::from(scene.0), f64::from(scene.1));
63    let (ow, oh) = (f64::from(out.0), f64::from(out.1));
64    let k = (ow / sw).min(oh / sh);
65    Affine::translate((ow / 2.0, oh / 2.0)) * Affine::scale(k)
66}