molgfx-render 0.3.3

The render graph, passes and the engine that drives a frame.
Documentation
use super::{MAGIC, VERSION};
use crate::engine::HdrImage;

#[test]
fn exr_preserves_native_half_channels_without_a_colour_curve() {
    let image = HdrImage {
        width: 1,
        height: 1,
        rgba16f: vec![0x00, 0x3c, 0x00, 0x40, 0x00, 0x42, 0x00, 0x38],
    };
    let bytes = encoded(&image);
    assert_eq!(&bytes[0..4], MAGIC.to_le_bytes());
    assert_eq!(&bytes[4..8], VERSION.to_le_bytes());
    let header_end = parse_header_end(&bytes);
    let block_offset = read_u64(&bytes, header_end);
    assert_eq!(block_offset, u64::try_from(header_end + 8).unwrap_or(0));
    let block = usize::try_from(block_offset).unwrap_or(0);
    assert_eq!(read_i32(&bytes, block), 0);
    assert_eq!(read_i32(&bytes, block + 4), 8);
    assert_eq!(
        &bytes[block + 8..block + 16],
        &[0x00, 0x38, 0x00, 0x42, 0x00, 0x40, 0x00, 0x3c],
        "OpenEXR scanlines are planar A, B, G, R"
    );
}

#[test]
fn exr_rejects_a_malformed_half_pixel_buffer() {
    let image = HdrImage {
        width: 2,
        height: 1,
        rgba16f: vec![0; 8],
    };
    assert!(super::write(&image, Vec::new()).is_err());
}

#[test]
fn streamed_exr_is_byte_deterministic() {
    let image = HdrImage {
        width: 2,
        height: 2,
        rgba16f: (0_u8..32).collect(),
    };
    assert_eq!(encoded(&image), encoded(&image));
}

fn encoded(image: &HdrImage) -> Vec<u8> {
    let mut output = Vec::new();
    if let Err(error) = super::write(image, &mut output) {
        panic!("streamed EXR encodes: {error}")
    }
    output
}

fn parse_header_end(bytes: &[u8]) -> usize {
    let mut cursor = 8;
    loop {
        let Some(&byte) = bytes.get(cursor) else {
            panic!("EXR header terminates")
        };
        if byte == 0 {
            return cursor + 1;
        }
        cursor = after_c_string(bytes, cursor);
        cursor = after_c_string(bytes, cursor);
        let size = usize::try_from(read_u32(bytes, cursor)).unwrap_or(0);
        cursor = cursor.saturating_add(4).saturating_add(size);
    }
}

fn after_c_string(bytes: &[u8], start: usize) -> usize {
    let Some(relative) = bytes
        .get(start..)
        .and_then(|tail| tail.iter().position(|byte| *byte == 0))
    else {
        panic!("EXR string terminates")
    };
    start + relative + 1
}

fn read_i32(bytes: &[u8], offset: usize) -> i32 {
    i32::from_le_bytes(read_array(bytes, offset))
}

fn read_u32(bytes: &[u8], offset: usize) -> u32 {
    u32::from_le_bytes(read_array(bytes, offset))
}

fn read_u64(bytes: &[u8], offset: usize) -> u64 {
    let Some(slice) = bytes.get(offset..offset + 8) else {
        panic!("EXR u64 exists")
    };
    let mut value = [0; 8];
    value.copy_from_slice(slice);
    u64::from_le_bytes(value)
}

fn read_array(bytes: &[u8], offset: usize) -> [u8; 4] {
    let Some(slice) = bytes.get(offset..offset + 4) else {
        panic!("EXR u32 exists")
    };
    let mut value = [0; 4];
    value.copy_from_slice(slice);
    value
}