use std::cell::RefCell;
use platform_headless::HeadlessWindow;
use renderer_core::RenderBackend;
use renderer_software::{SoftwareRenderer, SoftwareRendererConfig};
use crate::{Color, DrawCommand};
thread_local! {
static RASTERIZER: RefCell<Option<SoftwareRenderer<HeadlessWindow, HeadlessWindow>>> =
const { RefCell::new(None) };
}
pub fn rasterize(
commands: &[DrawCommand],
width: u32,
height: u32,
scale: f32,
clear_color: Option<Color>,
) -> Option<Vec<u8>> {
if width == 0 || height == 0 {
return None;
}
RASTERIZER.with(|cell| {
let mut slot = cell.borrow_mut();
let renderer = slot.get_or_insert_with(|| {
SoftwareRenderer::new_headless(width, height, SoftwareRendererConfig::default())
});
renderer.begin_frame(width, height, scale, 0).ok()?;
renderer.render_frame(commands, clear_color).ok()?;
renderer.read_rgba().map(<[u8]>::to_vec)
})
}
#[cfg(test)]
mod tests {
use super::*;
use geometry_core::Rect;
use renderer_core::{RectStyle, ShapeStyle};
use std::sync::Arc;
fn red_square(size: f32) -> Vec<DrawCommand> {
vec![DrawCommand::Rect {
rect: Rect::new(0.0, 0.0, size, size),
style: Arc::new(RectStyle::default().with_fill(Color::rgba(1.0, 0.0, 0.0, 1.0))),
}]
}
#[test]
fn it_draws_the_commands_it_is_given() {
let pixels = rasterize(&red_square(8.0), 8, 8, 1.0, None).expect("pixels");
assert_eq!(pixels.len(), 8 * 8 * 4);
let first = &pixels[0..4];
assert_eq!(
(first[0], first[3]),
(255, 255),
"an opaque red square must reach the buffer"
);
}
fn transparent_corner(pixels: &[u8]) -> u8 {
pixels[pixels.len() - 1]
}
#[test]
fn an_unset_clear_colour_leaves_the_background_transparent() {
let pixels = rasterize(&red_square(4.0), 16, 16, 1.0, None).expect("pixels");
assert_eq!(
transparent_corner(&pixels),
0,
"the area the commands did not cover stays clear"
);
}
#[test]
fn an_empty_size_is_none_rather_than_a_failure() {
assert!(rasterize(&red_square(4.0), 0, 8, 1.0, None).is_none());
assert!(rasterize(&red_square(4.0), 8, 0, 1.0, None).is_none());
}
#[test]
fn a_cached_renderer_still_resizes_between_calls() {
let small = rasterize(&red_square(4.0), 8, 8, 1.0, None).expect("small");
let large = rasterize(&red_square(4.0), 32, 24, 1.0, None).expect("large");
assert_eq!(small.len(), 8 * 8 * 4);
assert_eq!(large.len(), 32 * 24 * 4);
}
}