scena 1.7.2

A Rust-native scene-graph renderer with typed scene state, glTF assets, and explicit prepare/render lifecycles.
Documentation
use std::collections::{BTreeMap, BTreeSet};

use serde_json::json;

use super::checks::{CompositionCheckExt, checked_check, error_check, observed_pairs, round3};
use super::helpers::{draws_for_handles, projected_node_rect, visible_coverage_for_rect};
use super::object_pixels::object_pixel_quality_check;
use super::object_textures::object_texture_result_check;
use super::objects::ObjectCompositionInput;
use crate::SceneCompositionCheckV1;

pub(super) fn composition_import_checks(
    input: &ObjectCompositionInput<'_>,
    required_profile: Option<&str>,
    require_object_masks: bool,
) -> Vec<SceneCompositionCheckV1> {
    let mut checks = Vec::new();

    for import in &input.manifest.imports {
        let target_path = format!("import.{}", import.id);
        let mut handles = import
            .nodes_by_path
            .values()
            .copied()
            .collect::<BTreeSet<_>>();
        handles.extend(import.root_handles.iter().copied());
        if let Some(primary_root) = import.primary_root {
            handles.insert(primary_root);
        }
        if handles.is_empty() {
            checks.push(error_check(
                format!("{target_path}.presence"),
                "completeness",
                "declared_import_missing",
                Some(import.id.clone()),
                vec![import.import_handle],
                BTreeMap::new(),
                (
                    "declared recipe import has no manifest node handles",
                    "rebuild the recipe or remove the stale import",
                ),
            ));
            continue;
        }

        let representative_handle = import
            .primary_root
            .or_else(|| import.root_handles.first().copied())
            .or_else(|| handles.iter().next().copied())
            .unwrap_or(import.import_handle);
        let draws = draws_for_handles(input.inspection, &handles);
        if draws.is_empty() {
            checks.push(error_check(
                format!("{target_path}.presence"),
                "completeness",
                "declared_import_not_drawn",
                Some(import.id.clone()),
                handles.iter().copied().collect(),
                observed_pairs([
                    ("node_count", json!(handles.len())),
                    ("draw_count", json!(0_u64)),
                    ("uri", json!(import.uri)),
                ]),
                (
                    "declared import did not produce visible draw output",
                    "make the import visible, move it into frame, or remove the stale recipe import",
                ),
            ));
            continue;
        }

        checks.push(checked_check(
            format!("{target_path}.presence"),
            "completeness",
            "import_visible",
            Some(import.id.clone()),
            handles.iter().copied().collect(),
            observed_pairs([
                ("node_count", json!(handles.len())),
                ("draw_count", json!(draws.len())),
                ("uri", json!(import.uri)),
            ]),
            (
                "declared import is visible and contributes owned draw output",
                "no action needed",
            ),
        ));

        let projected_rect = projected_node_rect(input.capture, draws.as_slice());
        if let Some(rect) = projected_rect.filter(|rect| rect.width > 0.0 && rect.height > 0.0) {
            checks.push(
                checked_check(
                    format!("{target_path}.projected_bbox"),
                    "placement",
                    "projected_bbox_available",
                    Some(import.id.clone()),
                    vec![representative_handle],
                    observed_pairs([
                        ("width_px", json!(round3(rect.width))),
                        ("height_px", json!(round3(rect.height))),
                        ("center_x_px", json!(round3(rect.center_x))),
                        ("center_y_px", json!(round3(rect.center_y))),
                    ]),
                    (
                        "declared import has a projected screen region",
                        "no action needed",
                    ),
                )
                .with_region("import", Some(representative_handle), Some(rect)),
            );
        } else {
            checks.push(error_check(
                format!("{target_path}.projected_bbox"),
                "placement",
                "projected_bbox_missing",
                Some(import.id.clone()),
                handles.iter().copied().collect(),
                BTreeMap::new(),
                (
                    "declared import draws but its projected screen bounds could not be computed",
                    "check camera metadata and imported node bounds",
                ),
            ));
        }

        if let Some(coverage) = projected_rect
            .and_then(|rect| visible_coverage_for_rect(input.capture, rect, input.background))
        {
            if coverage.foreground_pixels > 0 {
                checks.push(
                    checked_check(
                        format!("{target_path}.visible_coverage"),
                        "occlusion_depth",
                        "visible_pixel_coverage_available",
                        Some(import.id.clone()),
                        vec![representative_handle],
                        observed_pairs([
                            ("region_pixels", json!(coverage.region_pixels)),
                            ("foreground_pixels", json!(coverage.foreground_pixels)),
                            (
                                "foreground_fraction",
                                json!(round3(coverage.foreground_fraction)),
                            ),
                        ]),
                        (
                            "declared import has measured non-background pixels in its projected screen region",
                            "no action needed",
                        ),
                    )
                    .with_region_from_screen("import", Some(representative_handle), coverage.region),
                );
                if let Some(profile) = required_profile {
                    checks.push(object_pixel_quality_check(
                        &target_path,
                        &import.id,
                        representative_handle,
                        input.capture,
                        coverage.region,
                        input.background,
                        profile,
                    ));
                    if let Some(check) = object_texture_result_check(
                        &target_path,
                        &import.id,
                        representative_handle,
                        input.capture,
                        coverage.region,
                        input.background,
                        draws.as_slice(),
                    ) {
                        checks.push(check);
                    }
                }
            } else {
                checks.push(
                    error_check(
                        format!("{target_path}.visible_coverage"),
                        "occlusion_depth",
                        "visible_pixel_coverage_missing",
                        Some(import.id.clone()),
                        vec![representative_handle],
                        observed_pairs([
                            ("region_pixels", json!(coverage.region_pixels)),
                            ("foreground_pixels", json!(coverage.foreground_pixels)),
                            (
                                "foreground_fraction",
                                json!(round3(coverage.foreground_fraction)),
                            ),
                            ("profile", json!(required_profile.unwrap_or_default())),
                        ]),
                        (
                            "declared import projects into the captured frame but contains no measured non-background pixels",
                            "move it into frame, make it visible, change its material/background contrast, or remove the stale import",
                        ),
                    )
                    .with_region_from_screen("import", Some(representative_handle), coverage.region),
                );
            }
        } else if require_object_masks {
            checks.push(error_check(
                format!("{target_path}.visible_coverage"),
                "occlusion_depth",
                "visible_pixel_coverage_missing",
                Some(import.id.clone()),
                vec![representative_handle],
                observed_pairs([("profile", json!(required_profile.unwrap_or_default()))]),
                (
                    "declared import has no viewport-clipped projected region for visible-pixel coverage",
                    "move it into the captured frame or remove the stale import",
                ),
            ));
        }
    }

    checks
}