scena 1.7.2

A Rust-native scene-graph renderer with typed scene state, glTF assets, and explicit prepare/render lifecycles.
Documentation
use super::*;

#[test]
fn matching_profile_sidecar_defers_hdr_decode_until_fallback_needed() {
    let path = "memory://uniform-studio.hdr";
    let bytes = rle_radiance_hdr_uniform(8, 1, [64, 32, 16, 129]);
    let sidecar = minimal_sidecar(&bytes);

    let desc = EnvironmentDesc::from_equirectangular_hdr_sidecar_bytes(path, &bytes, sidecar)
        .expect("sidecar env constructs")
        .expect("sidecar sha matches source");

    assert!(
        desc.prefilter_sidecar(EnvironmentSidecarProfile::InteractiveWebGl2)
            .is_some(),
        "precondition: the WebGL2 sidecar must satisfy a matching WebGL2 request"
    );
    assert!(
        desc.equirectangular_pixels.is_none(),
        "matching-profile sidecar loads must not decode and retain the HDR pixel grid; \
         decode is only allowed when a later profile-mismatch fallback needs a fresh bake"
    );
    assert!(
        desc.lazy_equirectangular_source.is_some(),
        "sidecar-backed environments must retain compressed HDR source bytes for a later \
         profile-mismatch fallback"
    );
}

fn minimal_sidecar(source_bytes: &[u8]) -> EnvironmentPrefilterSidecar {
    let face = vec![0.5, 0.5, 0.5, 1.0];
    let mip = [
        face.clone(),
        face.clone(),
        face.clone(),
        face.clone(),
        face.clone(),
        face,
    ];
    EnvironmentPrefilterSidecar::new(
        EnvironmentSidecarProfile::InteractiveWebGl2,
        &sha256_hex(source_bytes),
        1,
        vec![mip],
        vec![1.0, 0.0, 1.0, 0.0],
        1,
        [0.5, 0.5, 0.5],
    )
    .expect("minimal sidecar is valid")
}

fn rle_radiance_hdr_uniform(width: u32, height: u32, rgbe: [u8; 4]) -> Vec<u8> {
    assert!(width >= 8);
    assert!(width <= 127);
    let mut bytes =
        format!("#?RADIANCE\nFORMAT=32-bit_rle_rgbe\n\n-Y {height} +X {width}\n").into_bytes();
    for _ in 0..height {
        bytes.push(0x02);
        bytes.push(0x02);
        bytes.push((width >> 8) as u8);
        bytes.push((width & 0xff) as u8);
        for channel in &rgbe {
            bytes.push(0x80 + width as u8);
            bytes.push(*channel);
        }
    }
    bytes
}